blob: f698901e5bc04c11bc2623cd4022ffd95389a26b [file] [log] [blame]
Lewanczyk, Dawid88d16c92018-02-02 14:51:09 +01001/*
2// Copyright (c) 2018 Intel Corporation
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15*/
16#pragma once
Lewanczyk, Dawid88d16c92018-02-02 14:51:09 +010017#include "node.hpp"
18
Ratan Gupta24c85422019-01-30 19:41:24 +053019#include <dbus_utility.hpp>
Ed Tanous65b0dc32018-09-19 16:04:03 -070020#include <error_messages.hpp>
Ed Tanousb9b2e0b2018-09-13 13:47:50 -070021#include <openbmc_dbus_rest.hpp>
Ed Tanousa8408792018-09-05 16:08:38 -070022#include <utils/json_utils.hpp>
Ed Tanousabf2add2019-01-22 16:40:12 -080023#include <variant>
Ed Tanousb9b2e0b2018-09-13 13:47:50 -070024
Ed Tanous1abe55e2018-09-05 08:30:59 -070025namespace redfish
26{
Lewanczyk, Dawid88d16c92018-02-02 14:51:09 +010027
Ed Tanousb9b2e0b2018-09-13 13:47:50 -070028using ManagedObjectType = std::vector<std::pair<
29 sdbusplus::message::object_path,
30 boost::container::flat_map<
Ed Tanousabf2add2019-01-22 16:40:12 -080031 std::string, boost::container::flat_map<
32 std::string, std::variant<bool, std::string>>>>>;
AppaRao Puli84e12cb2018-10-11 01:28:15 +053033
34inline std::string getPrivilegeFromRoleId(boost::beast::string_view role)
35{
36 if (role == "priv-admin")
37 {
38 return "Administrator";
39 }
40 else if (role == "priv-callback")
41 {
42 return "Callback";
43 }
44 else if (role == "priv-user")
45 {
46 return "User";
47 }
48 else if (role == "priv-operator")
49 {
50 return "Operator";
51 }
52 return "";
53}
54inline std::string getRoleIdFromPrivilege(boost::beast::string_view role)
55{
56 if (role == "Administrator")
57 {
58 return "priv-admin";
59 }
60 else if (role == "Callback")
61 {
62 return "priv-callback";
63 }
64 else if (role == "User")
65 {
66 return "priv-user";
67 }
68 else if (role == "Operator")
69 {
70 return "priv-operator";
71 }
72 return "";
73}
Ed Tanousb9b2e0b2018-09-13 13:47:50 -070074
Ed Tanous1abe55e2018-09-05 08:30:59 -070075class AccountService : public Node
76{
77 public:
78 AccountService(CrowApp& app) : Node(app, "/redfish/v1/AccountService/")
79 {
Ed Tanous1abe55e2018-09-05 08:30:59 -070080 entityPrivileges = {
81 {boost::beast::http::verb::get,
82 {{"ConfigureUsers"}, {"ConfigureManager"}}},
83 {boost::beast::http::verb::head, {{"Login"}}},
84 {boost::beast::http::verb::patch, {{"ConfigureUsers"}}},
85 {boost::beast::http::verb::put, {{"ConfigureUsers"}}},
86 {boost::beast::http::verb::delete_, {{"ConfigureUsers"}}},
87 {boost::beast::http::verb::post, {{"ConfigureUsers"}}}};
88 }
Lewanczyk, Dawid88d16c92018-02-02 14:51:09 +010089
Ed Tanous1abe55e2018-09-05 08:30:59 -070090 private:
91 void doGet(crow::Response& res, const crow::Request& req,
92 const std::vector<std::string>& params) override
93 {
AppaRao Puli3d958bb2018-12-25 12:45:54 +053094 auto asyncResp = std::make_shared<AsyncResp>(res);
95 res.jsonValue = {
96 {"@odata.context", "/redfish/v1/"
97 "$metadata#AccountService.AccountService"},
98 {"@odata.id", "/redfish/v1/AccountService"},
99 {"@odata.type", "#AccountService."
100 "v1_1_0.AccountService"},
101 {"Id", "AccountService"},
102 {"Name", "Account Service"},
103 {"Description", "Account Service"},
104 {"ServiceEnabled", true},
105 {"MaxPasswordLength", 31},
106 {"Accounts",
107 {{"@odata.id", "/redfish/v1/AccountService/Accounts"}}},
108 {"Roles", {{"@odata.id", "/redfish/v1/AccountService/Roles"}}}};
Ed Tanous0f74e642018-11-12 15:17:05 -0800109
AppaRao Puli3d958bb2018-12-25 12:45:54 +0530110 crow::connections::systemBus->async_method_call(
111 [asyncResp](
112 const boost::system::error_code ec,
113 const std::vector<std::pair<
Ed Tanousabf2add2019-01-22 16:40:12 -0800114 std::string, std::variant<uint32_t, uint16_t, uint8_t>>>&
AppaRao Puli3d958bb2018-12-25 12:45:54 +0530115 propertiesList) {
116 if (ec)
117 {
118 messages::internalError(asyncResp->res);
119 return;
120 }
121 BMCWEB_LOG_DEBUG << "Got " << propertiesList.size()
122 << "properties for AccountService";
123 for (const std::pair<std::string,
Ed Tanousabf2add2019-01-22 16:40:12 -0800124 std::variant<uint32_t, uint16_t, uint8_t>>&
AppaRao Puli3d958bb2018-12-25 12:45:54 +0530125 property : propertiesList)
126 {
127 if (property.first == "MinPasswordLength")
128 {
129 const uint8_t* value =
Ed Tanousabf2add2019-01-22 16:40:12 -0800130 std::get_if<uint8_t>(&property.second);
AppaRao Puli3d958bb2018-12-25 12:45:54 +0530131 if (value != nullptr)
132 {
133 asyncResp->res.jsonValue["MinPasswordLength"] =
134 *value;
135 }
136 }
137 if (property.first == "AccountUnlockTimeout")
138 {
139 const uint32_t* value =
Ed Tanousabf2add2019-01-22 16:40:12 -0800140 std::get_if<uint32_t>(&property.second);
AppaRao Puli3d958bb2018-12-25 12:45:54 +0530141 if (value != nullptr)
142 {
143 asyncResp->res.jsonValue["AccountLockoutDuration"] =
144 *value;
145 }
146 }
147 if (property.first == "MaxLoginAttemptBeforeLockout")
148 {
149 const uint16_t* value =
Ed Tanousabf2add2019-01-22 16:40:12 -0800150 std::get_if<uint16_t>(&property.second);
AppaRao Puli3d958bb2018-12-25 12:45:54 +0530151 if (value != nullptr)
152 {
153 asyncResp->res
154 .jsonValue["AccountLockoutThreshold"] = *value;
155 }
156 }
157 }
158 },
159 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
160 "org.freedesktop.DBus.Properties", "GetAll",
161 "xyz.openbmc_project.User.AccountPolicy");
162 }
163 void doPatch(crow::Response& res, const crow::Request& req,
164 const std::vector<std::string>& params) override
165 {
166 auto asyncResp = std::make_shared<AsyncResp>(res);
167
168 std::optional<uint32_t> unlockTimeout;
169 std::optional<uint16_t> lockoutThreshold;
170 if (!json_util::readJson(req, res, "AccountLockoutDuration",
171 unlockTimeout, "AccountLockoutThreshold",
172 lockoutThreshold))
173 {
174 return;
175 }
176 if (unlockTimeout)
177 {
178 crow::connections::systemBus->async_method_call(
179 [asyncResp](const boost::system::error_code ec) {
180 if (ec)
181 {
182 messages::internalError(asyncResp->res);
183 return;
184 }
185 },
186 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
187 "org.freedesktop.DBus.Properties", "Set",
188 "xyz.openbmc_project.User.AccountPolicy",
Ed Tanousabf2add2019-01-22 16:40:12 -0800189 "AccountUnlockTimeout", std::variant<uint32_t>(*unlockTimeout));
AppaRao Puli3d958bb2018-12-25 12:45:54 +0530190 }
191 if (lockoutThreshold)
192 {
193 crow::connections::systemBus->async_method_call(
194 [asyncResp](const boost::system::error_code ec) {
195 if (ec)
196 {
197 messages::internalError(asyncResp->res);
198 return;
199 }
200 },
201 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
202 "org.freedesktop.DBus.Properties", "Set",
203 "xyz.openbmc_project.User.AccountPolicy",
204 "MaxLoginAttemptBeforeLockout",
Ed Tanousabf2add2019-01-22 16:40:12 -0800205 std::variant<uint16_t>(*lockoutThreshold));
AppaRao Puli3d958bb2018-12-25 12:45:54 +0530206 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700207 }
Lewanczyk, Dawid88d16c92018-02-02 14:51:09 +0100208};
Ed Tanousb9b2e0b2018-09-13 13:47:50 -0700209class AccountsCollection : public Node
210{
211 public:
212 AccountsCollection(CrowApp& app) :
213 Node(app, "/redfish/v1/AccountService/Accounts/")
214 {
Ed Tanousb9b2e0b2018-09-13 13:47:50 -0700215 entityPrivileges = {
216 {boost::beast::http::verb::get,
217 {{"ConfigureUsers"}, {"ConfigureManager"}}},
218 {boost::beast::http::verb::head, {{"Login"}}},
219 {boost::beast::http::verb::patch, {{"ConfigureUsers"}}},
220 {boost::beast::http::verb::put, {{"ConfigureUsers"}}},
221 {boost::beast::http::verb::delete_, {{"ConfigureUsers"}}},
222 {boost::beast::http::verb::post, {{"ConfigureUsers"}}}};
223 }
224
225 private:
226 void doGet(crow::Response& res, const crow::Request& req,
227 const std::vector<std::string>& params) override
228 {
Ed Tanousb9b2e0b2018-09-13 13:47:50 -0700229 auto asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous0f74e642018-11-12 15:17:05 -0800230 res.jsonValue = {{"@odata.context",
231 "/redfish/v1/"
232 "$metadata#ManagerAccountCollection."
233 "ManagerAccountCollection"},
234 {"@odata.id", "/redfish/v1/AccountService/Accounts"},
235 {"@odata.type", "#ManagerAccountCollection."
236 "ManagerAccountCollection"},
237 {"Name", "Accounts Collection"},
238 {"Description", "BMC User Accounts"}};
239
Ed Tanousb9b2e0b2018-09-13 13:47:50 -0700240 crow::connections::systemBus->async_method_call(
241 [asyncResp](const boost::system::error_code ec,
242 const ManagedObjectType& users) {
243 if (ec)
244 {
Jason M. Billsf12894f2018-10-09 12:45:45 -0700245 messages::internalError(asyncResp->res);
Ed Tanousb9b2e0b2018-09-13 13:47:50 -0700246 return;
247 }
248
249 nlohmann::json& memberArray =
250 asyncResp->res.jsonValue["Members"];
251 memberArray = nlohmann::json::array();
252
253 asyncResp->res.jsonValue["Members@odata.count"] = users.size();
254 for (auto& user : users)
255 {
256 const std::string& path =
257 static_cast<const std::string&>(user.first);
258 std::size_t lastIndex = path.rfind("/");
259 if (lastIndex == std::string::npos)
260 {
261 lastIndex = 0;
262 }
263 else
264 {
265 lastIndex += 1;
266 }
267 memberArray.push_back(
268 {{"@odata.id", "/redfish/v1/AccountService/Accounts/" +
269 path.substr(lastIndex)}});
270 }
271 },
272 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
273 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
274 }
Ed Tanous04ae99e2018-09-20 15:54:36 -0700275 void doPost(crow::Response& res, const crow::Request& req,
276 const std::vector<std::string>& params) override
277 {
278 auto asyncResp = std::make_shared<AsyncResp>(res);
279
Ed Tanous9712f8a2018-09-21 13:38:49 -0700280 std::string username;
281 std::string password;
Ed Tanousa24526d2018-12-10 15:17:59 -0800282 std::optional<std::string> roleId("User");
283 std::optional<bool> enabled = true;
Ed Tanous9712f8a2018-09-21 13:38:49 -0700284 if (!json_util::readJson(req, res, "UserName", username, "Password",
285 password, "RoleId", roleId, "Enabled",
286 enabled))
Ed Tanous04ae99e2018-09-20 15:54:36 -0700287 {
288 return;
289 }
290
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530291 std::string priv = getRoleIdFromPrivilege(*roleId);
292 if (priv.empty())
Ed Tanous04ae99e2018-09-20 15:54:36 -0700293 {
Jason M. Billsf12894f2018-10-09 12:45:45 -0700294 messages::propertyValueNotInList(asyncResp->res, *roleId, "RoleId");
Ed Tanous04ae99e2018-09-20 15:54:36 -0700295 return;
296 }
Ed Tanous9712f8a2018-09-21 13:38:49 -0700297 roleId = priv;
Ed Tanous04ae99e2018-09-20 15:54:36 -0700298
299 crow::connections::systemBus->async_method_call(
Ed Tanous9712f8a2018-09-21 13:38:49 -0700300 [asyncResp, username, password{std::move(password)}](
Ed Tanous04ae99e2018-09-20 15:54:36 -0700301 const boost::system::error_code ec) {
302 if (ec)
303 {
Jason M. Billsf12894f2018-10-09 12:45:45 -0700304 messages::resourceAlreadyExists(
305 asyncResp->res, "#ManagerAccount.v1_0_3.ManagerAccount",
306 "UserName", username);
Ed Tanous04ae99e2018-09-20 15:54:36 -0700307 return;
308 }
309
310 if (!pamUpdatePassword(username, password))
311 {
312 // At this point we have a user that's been created, but the
313 // password set failed. Something is wrong, so delete the
314 // user that we've already created
315 crow::connections::systemBus->async_method_call(
316 [asyncResp](const boost::system::error_code ec) {
317 if (ec)
318 {
Jason M. Billsf12894f2018-10-09 12:45:45 -0700319 messages::internalError(asyncResp->res);
Ed Tanous04ae99e2018-09-20 15:54:36 -0700320 return;
321 }
322
Jason M. Billsf12894f2018-10-09 12:45:45 -0700323 messages::invalidObject(asyncResp->res, "Password");
Ed Tanous04ae99e2018-09-20 15:54:36 -0700324 },
325 "xyz.openbmc_project.User.Manager",
326 "/xyz/openbmc_project/user/" + username,
327 "xyz.openbmc_project.Object.Delete", "Delete");
328
329 BMCWEB_LOG_ERROR << "pamUpdatePassword Failed";
330 return;
331 }
332
Jason M. Billsf12894f2018-10-09 12:45:45 -0700333 messages::created(asyncResp->res);
Ed Tanous04ae99e2018-09-20 15:54:36 -0700334 asyncResp->res.addHeader(
335 "Location",
336 "/redfish/v1/AccountService/Accounts/" + username);
337 },
338 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
Ed Tanous9712f8a2018-09-21 13:38:49 -0700339 "xyz.openbmc_project.User.Manager", "CreateUser", username,
Ed Tanous04ae99e2018-09-20 15:54:36 -0700340 std::array<const char*, 4>{"ipmi", "redfish", "ssh", "web"},
Ed Tanous9712f8a2018-09-21 13:38:49 -0700341 *roleId, *enabled);
Ed Tanous04ae99e2018-09-20 15:54:36 -0700342 }
Ed Tanousb9b2e0b2018-09-13 13:47:50 -0700343};
344
Ed Tanousa8408792018-09-05 16:08:38 -0700345template <typename Callback>
346inline void checkDbusPathExists(const std::string& path, Callback&& callback)
347{
348 using GetObjectType =
349 std::vector<std::pair<std::string, std::vector<std::string>>>;
350
351 crow::connections::systemBus->async_method_call(
352 [callback{std::move(callback)}](const boost::system::error_code ec,
353 const GetObjectType& object_names) {
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530354 callback(!ec && object_names.size() != 0);
Ed Tanousa8408792018-09-05 16:08:38 -0700355 },
356 "xyz.openbmc_project.ObjectMapper",
357 "/xyz/openbmc_project/object_mapper",
358 "xyz.openbmc_project.ObjectMapper", "GetObject", path,
359 std::array<std::string, 0>());
360}
361
Ed Tanousb9b2e0b2018-09-13 13:47:50 -0700362class ManagerAccount : public Node
363{
364 public:
365 ManagerAccount(CrowApp& app) :
366 Node(app, "/redfish/v1/AccountService/Accounts/<str>/", std::string())
367 {
Ed Tanousb9b2e0b2018-09-13 13:47:50 -0700368 entityPrivileges = {
369 {boost::beast::http::verb::get,
370 {{"ConfigureUsers"}, {"ConfigureManager"}, {"ConfigureSelf"}}},
371 {boost::beast::http::verb::head, {{"Login"}}},
372 {boost::beast::http::verb::patch, {{"ConfigureUsers"}}},
373 {boost::beast::http::verb::put, {{"ConfigureUsers"}}},
374 {boost::beast::http::verb::delete_, {{"ConfigureUsers"}}},
375 {boost::beast::http::verb::post, {{"ConfigureUsers"}}}};
376 }
377
378 private:
379 void doGet(crow::Response& res, const crow::Request& req,
380 const std::vector<std::string>& params) override
381 {
Ed Tanous0f74e642018-11-12 15:17:05 -0800382 res.jsonValue = {
383 {"@odata.context",
384 "/redfish/v1/$metadata#ManagerAccount.ManagerAccount"},
385 {"@odata.type", "#ManagerAccount.v1_0_3.ManagerAccount"},
Ed Tanous0f74e642018-11-12 15:17:05 -0800386 {"Name", "User Account"},
387 {"Description", "User Account"},
388 {"Password", nullptr},
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530389 {"RoleId", "Administrator"}};
Ed Tanous0f74e642018-11-12 15:17:05 -0800390
Ed Tanousb9b2e0b2018-09-13 13:47:50 -0700391 auto asyncResp = std::make_shared<AsyncResp>(res);
392
393 if (params.size() != 1)
394 {
Jason M. Billsf12894f2018-10-09 12:45:45 -0700395 messages::internalError(asyncResp->res);
Ed Tanousb9b2e0b2018-09-13 13:47:50 -0700396 return;
397 }
398
399 crow::connections::systemBus->async_method_call(
400 [asyncResp, accountName{std::string(params[0])}](
401 const boost::system::error_code ec,
402 const ManagedObjectType& users) {
403 if (ec)
404 {
Jason M. Billsf12894f2018-10-09 12:45:45 -0700405 messages::internalError(asyncResp->res);
Ed Tanousb9b2e0b2018-09-13 13:47:50 -0700406 return;
407 }
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530408 auto userIt = users.begin();
Ed Tanousb9b2e0b2018-09-13 13:47:50 -0700409
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530410 for (; userIt != users.end(); userIt++)
Ed Tanousb9b2e0b2018-09-13 13:47:50 -0700411 {
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530412 if (boost::ends_with(userIt->first.str, "/" + accountName))
Ed Tanousb9b2e0b2018-09-13 13:47:50 -0700413 {
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530414 break;
Ed Tanousb9b2e0b2018-09-13 13:47:50 -0700415 }
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530416 }
417 if (userIt == users.end())
418 {
419 messages::resourceNotFound(asyncResp->res, "ManagerAccount",
420 accountName);
421 return;
422 }
423 for (const auto& interface : userIt->second)
424 {
425 if (interface.first ==
426 "xyz.openbmc_project.User.Attributes")
Ed Tanousb9b2e0b2018-09-13 13:47:50 -0700427 {
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530428 for (const auto& property : interface.second)
Ed Tanous65b0dc32018-09-19 16:04:03 -0700429 {
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530430 if (property.first == "UserEnabled")
Ed Tanous65b0dc32018-09-19 16:04:03 -0700431 {
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530432 const bool* userEnabled =
Ed Tanousabf2add2019-01-22 16:40:12 -0800433 std::get_if<bool>(&property.second);
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530434 if (userEnabled == nullptr)
Ed Tanous65b0dc32018-09-19 16:04:03 -0700435 {
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530436 BMCWEB_LOG_ERROR
437 << "UserEnabled wasn't a bool";
438 messages::internalError(asyncResp->res);
439 return;
Ed Tanous65b0dc32018-09-19 16:04:03 -0700440 }
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530441 asyncResp->res.jsonValue["Enabled"] =
442 *userEnabled;
443 }
444 else if (property.first ==
445 "UserLockedForFailedAttempt")
446 {
447 const bool* userLocked =
Ed Tanousabf2add2019-01-22 16:40:12 -0800448 std::get_if<bool>(&property.second);
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530449 if (userLocked == nullptr)
450 {
451 BMCWEB_LOG_ERROR << "UserLockedForF"
452 "ailedAttempt "
453 "wasn't a bool";
454 messages::internalError(asyncResp->res);
455 return;
456 }
457 asyncResp->res.jsonValue["Locked"] =
458 *userLocked;
Ratan Gupta24c85422019-01-30 19:41:24 +0530459 asyncResp->res.jsonValue
460 ["Locked@Redfish.AllowableValues"] = {
461 false};
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530462 }
463 else if (property.first == "UserPrivilege")
464 {
465 const std::string* userRolePtr =
Ed Tanousabf2add2019-01-22 16:40:12 -0800466 std::get_if<std::string>(&property.second);
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530467 if (userRolePtr == nullptr)
468 {
469 BMCWEB_LOG_ERROR
470 << "UserPrivilege wasn't a "
471 "string";
472 messages::internalError(asyncResp->res);
473 return;
474 }
475 std::string priv =
476 getPrivilegeFromRoleId(*userRolePtr);
477 if (priv.empty())
478 {
479 BMCWEB_LOG_ERROR << "Invalid user role";
480 messages::internalError(asyncResp->res);
481 return;
482 }
483 asyncResp->res.jsonValue["RoleId"] = priv;
484
485 asyncResp->res.jsonValue["Links"]["Role"] = {
486 {"@odata.id", "/redfish/v1/AccountService/"
487 "Roles/" +
488 priv}};
Ed Tanous65b0dc32018-09-19 16:04:03 -0700489 }
490 }
Ed Tanousb9b2e0b2018-09-13 13:47:50 -0700491 }
492 }
493
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530494 asyncResp->res.jsonValue["@odata.id"] =
495 "/redfish/v1/AccountService/Accounts/" + accountName;
496 asyncResp->res.jsonValue["Id"] = accountName;
497 asyncResp->res.jsonValue["UserName"] = accountName;
Ed Tanousb9b2e0b2018-09-13 13:47:50 -0700498 },
499 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
500 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
501 }
Ed Tanousa8408792018-09-05 16:08:38 -0700502
503 void doPatch(crow::Response& res, const crow::Request& req,
504 const std::vector<std::string>& params) override
505 {
506 auto asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanousa8408792018-09-05 16:08:38 -0700507 if (params.size() != 1)
508 {
Jason M. Billsf12894f2018-10-09 12:45:45 -0700509 messages::internalError(asyncResp->res);
Ed Tanousa8408792018-09-05 16:08:38 -0700510 return;
511 }
512
Ed Tanousa24526d2018-12-10 15:17:59 -0800513 std::optional<std::string> newUserName;
514 std::optional<std::string> password;
515 std::optional<bool> enabled;
516 std::optional<std::string> roleId;
Ratan Gupta24c85422019-01-30 19:41:24 +0530517 std::optional<bool> locked;
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530518 if (!json_util::readJson(req, res, "UserName", newUserName, "Password",
Ratan Gupta24c85422019-01-30 19:41:24 +0530519 password, "RoleId", roleId, "Enabled", enabled,
520 "Locked", locked))
Ed Tanousa8408792018-09-05 16:08:38 -0700521 {
522 return;
523 }
524
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530525 const std::string& username = params[0];
Ed Tanousa8408792018-09-05 16:08:38 -0700526
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530527 if (!newUserName)
528 {
529 // If the username isn't being updated, we can update the properties
530 // directly
Ratan Gupta24c85422019-01-30 19:41:24 +0530531 updateUserProperties(asyncResp, username, password, enabled, roleId,
532 locked);
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530533 return;
534 }
535 else
536 {
537 crow::connections::systemBus->async_method_call(
538 [this, asyncResp, username, password(std::move(password)),
539 roleId(std::move(roleId)), enabled(std::move(enabled)),
Ratan Gupta24c85422019-01-30 19:41:24 +0530540 newUser{std::string(*newUserName)}, locked(std::move(locked))](
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530541 const boost::system::error_code ec) {
542 if (ec)
Ed Tanousa8408792018-09-05 16:08:38 -0700543 {
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530544 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
545 messages::resourceNotFound(
546 asyncResp->res,
547 "#ManagerAccount.v1_0_3.ManagerAccount", username);
548 return;
549 }
550
551 updateUserProperties(asyncResp, newUser, password, enabled,
Ratan Gupta24c85422019-01-30 19:41:24 +0530552 roleId, locked);
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530553 },
554 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
555 "xyz.openbmc_project.User.Manager", "RenameUser", username,
556 *newUserName);
557 }
558 }
559
560 void updateUserProperties(std::shared_ptr<AsyncResp> asyncResp,
561 const std::string& username,
Ed Tanousa24526d2018-12-10 15:17:59 -0800562 std::optional<std::string> password,
563 std::optional<bool> enabled,
Ratan Gupta24c85422019-01-30 19:41:24 +0530564 std::optional<std::string> roleId,
565 std::optional<bool> locked)
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530566 {
567 if (password)
568 {
569 if (!pamUpdatePassword(username, *password))
570 {
571 BMCWEB_LOG_ERROR << "pamUpdatePassword Failed";
572 messages::internalError(asyncResp->res);
573 return;
574 }
575 }
576
Ratan Gupta24c85422019-01-30 19:41:24 +0530577 std::string dbusObjectPath = "/xyz/openbmc_project/user/" + username;
578 dbus::utility::escapePathForDbus(dbusObjectPath);
579
580 checkDbusPathExists(
581 dbusObjectPath,
582 [dbusObjectPath(std::move(dbusObjectPath)), username,
583 password(std::move(password)), roleId(std::move(roleId)),
584 enabled(std::move(enabled)), locked(std::move(locked)),
585 asyncResp{std::move(asyncResp)}](int rc) {
586 if (!rc)
587 {
588 messages::invalidObject(asyncResp->res, username.c_str());
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530589 return;
Ratan Gupta24c85422019-01-30 19:41:24 +0530590 }
591 if (enabled)
592 {
593 crow::connections::systemBus->async_method_call(
594 [asyncResp](const boost::system::error_code ec) {
595 if (ec)
596 {
597 BMCWEB_LOG_ERROR << "D-Bus responses error: "
598 << ec;
599 messages::internalError(asyncResp->res);
600 return;
601 }
602 messages::success(asyncResp->res);
603 return;
604 },
605 "xyz.openbmc_project.User.Manager",
606 dbusObjectPath.c_str(),
607 "org.freedesktop.DBus.Properties", "Set",
608 "xyz.openbmc_project.User.Attributes", "UserEnabled",
609 std::variant<bool>{*enabled});
610 }
Ed Tanous9712f8a2018-09-21 13:38:49 -0700611
Ratan Gupta24c85422019-01-30 19:41:24 +0530612 if (roleId)
613 {
614 std::string priv = getRoleIdFromPrivilege(*roleId);
615 if (priv.empty())
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530616 {
Ratan Gupta24c85422019-01-30 19:41:24 +0530617 messages::propertyValueNotInList(asyncResp->res,
618 *roleId, "RoleId");
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530619 return;
620 }
Ratan Gupta24c85422019-01-30 19:41:24 +0530621
622 crow::connections::systemBus->async_method_call(
623 [asyncResp](const boost::system::error_code ec) {
624 if (ec)
625 {
626 BMCWEB_LOG_ERROR << "D-Bus responses error: "
627 << ec;
628 messages::internalError(asyncResp->res);
629 return;
630 }
631 messages::success(asyncResp->res);
632 },
633 "xyz.openbmc_project.User.Manager",
634 dbusObjectPath.c_str(),
635 "org.freedesktop.DBus.Properties", "Set",
636 "xyz.openbmc_project.User.Attributes", "UserPrivilege",
637 std::variant<std::string>{priv});
638 }
639
640 if (locked)
641 {
642 // admin can unlock the account which is locked by
643 // successive authentication failures but admin should not
644 // be allowed to lock an account.
645 if (*locked)
646 {
647 messages::propertyValueNotInList(asyncResp->res, "true",
648 "Locked");
649 return;
650 }
651
652 crow::connections::systemBus->async_method_call(
653 [asyncResp](const boost::system::error_code ec) {
654 if (ec)
655 {
656 BMCWEB_LOG_ERROR << "D-Bus responses error: "
657 << ec;
658 messages::internalError(asyncResp->res);
659 return;
660 }
661 messages::success(asyncResp->res);
662 return;
663 },
664 "xyz.openbmc_project.User.Manager",
665 dbusObjectPath.c_str(),
666 "org.freedesktop.DBus.Properties", "Set",
667 "xyz.openbmc_project.User.Attributes",
668 "UserLockedForFailedAttempt",
669 sdbusplus::message::variant<bool>{*locked});
670 }
671 });
Ed Tanousa8408792018-09-05 16:08:38 -0700672 }
Ed Tanous06e086d2018-09-19 17:19:52 -0700673
674 void doDelete(crow::Response& res, const crow::Request& req,
675 const std::vector<std::string>& params) override
676 {
677 auto asyncResp = std::make_shared<AsyncResp>(res);
678
679 if (params.size() != 1)
680 {
Jason M. Billsf12894f2018-10-09 12:45:45 -0700681 messages::internalError(asyncResp->res);
Ed Tanous06e086d2018-09-19 17:19:52 -0700682 return;
683 }
684
685 const std::string userPath = "/xyz/openbmc_project/user/" + params[0];
686
687 crow::connections::systemBus->async_method_call(
688 [asyncResp, username{std::move(params[0])}](
689 const boost::system::error_code ec) {
690 if (ec)
691 {
Jason M. Billsf12894f2018-10-09 12:45:45 -0700692 messages::resourceNotFound(
693 asyncResp->res, "#ManagerAccount.v1_0_3.ManagerAccount",
694 username);
Ed Tanous06e086d2018-09-19 17:19:52 -0700695 return;
696 }
697
Jason M. Billsf12894f2018-10-09 12:45:45 -0700698 messages::accountRemoved(asyncResp->res);
Ed Tanous06e086d2018-09-19 17:19:52 -0700699 },
700 "xyz.openbmc_project.User.Manager", userPath,
701 "xyz.openbmc_project.Object.Delete", "Delete");
702 }
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530703};
Lewanczyk, Dawid88d16c92018-02-02 14:51:09 +0100704
Ed Tanous1abe55e2018-09-05 08:30:59 -0700705} // namespace redfish