blob: 045f40c4e824c93af70d8ee41fdb9cdec1c2bcb4 [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 }
Ratan Guptaadd61332019-02-13 20:49:16 +0530185 messages::success(asyncResp->res);
AppaRao Puli3d958bb2018-12-25 12:45:54 +0530186 },
187 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
188 "org.freedesktop.DBus.Properties", "Set",
189 "xyz.openbmc_project.User.AccountPolicy",
Ed Tanousabf2add2019-01-22 16:40:12 -0800190 "AccountUnlockTimeout", std::variant<uint32_t>(*unlockTimeout));
AppaRao Puli3d958bb2018-12-25 12:45:54 +0530191 }
192 if (lockoutThreshold)
193 {
194 crow::connections::systemBus->async_method_call(
195 [asyncResp](const boost::system::error_code ec) {
196 if (ec)
197 {
198 messages::internalError(asyncResp->res);
199 return;
200 }
Ratan Guptaadd61332019-02-13 20:49:16 +0530201 messages::success(asyncResp->res);
AppaRao Puli3d958bb2018-12-25 12:45:54 +0530202 },
203 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
204 "org.freedesktop.DBus.Properties", "Set",
205 "xyz.openbmc_project.User.AccountPolicy",
206 "MaxLoginAttemptBeforeLockout",
Ed Tanousabf2add2019-01-22 16:40:12 -0800207 std::variant<uint16_t>(*lockoutThreshold));
AppaRao Puli3d958bb2018-12-25 12:45:54 +0530208 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700209 }
Lewanczyk, Dawid88d16c92018-02-02 14:51:09 +0100210};
Ed Tanousb9b2e0b2018-09-13 13:47:50 -0700211class AccountsCollection : public Node
212{
213 public:
214 AccountsCollection(CrowApp& app) :
215 Node(app, "/redfish/v1/AccountService/Accounts/")
216 {
Ed Tanousb9b2e0b2018-09-13 13:47:50 -0700217 entityPrivileges = {
218 {boost::beast::http::verb::get,
219 {{"ConfigureUsers"}, {"ConfigureManager"}}},
220 {boost::beast::http::verb::head, {{"Login"}}},
221 {boost::beast::http::verb::patch, {{"ConfigureUsers"}}},
222 {boost::beast::http::verb::put, {{"ConfigureUsers"}}},
223 {boost::beast::http::verb::delete_, {{"ConfigureUsers"}}},
224 {boost::beast::http::verb::post, {{"ConfigureUsers"}}}};
225 }
226
227 private:
228 void doGet(crow::Response& res, const crow::Request& req,
229 const std::vector<std::string>& params) override
230 {
Ed Tanousb9b2e0b2018-09-13 13:47:50 -0700231 auto asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous0f74e642018-11-12 15:17:05 -0800232 res.jsonValue = {{"@odata.context",
233 "/redfish/v1/"
234 "$metadata#ManagerAccountCollection."
235 "ManagerAccountCollection"},
236 {"@odata.id", "/redfish/v1/AccountService/Accounts"},
237 {"@odata.type", "#ManagerAccountCollection."
238 "ManagerAccountCollection"},
239 {"Name", "Accounts Collection"},
240 {"Description", "BMC User Accounts"}};
241
Ed Tanousb9b2e0b2018-09-13 13:47:50 -0700242 crow::connections::systemBus->async_method_call(
243 [asyncResp](const boost::system::error_code ec,
244 const ManagedObjectType& users) {
245 if (ec)
246 {
Jason M. Billsf12894f2018-10-09 12:45:45 -0700247 messages::internalError(asyncResp->res);
Ed Tanousb9b2e0b2018-09-13 13:47:50 -0700248 return;
249 }
250
251 nlohmann::json& memberArray =
252 asyncResp->res.jsonValue["Members"];
253 memberArray = nlohmann::json::array();
254
255 asyncResp->res.jsonValue["Members@odata.count"] = users.size();
256 for (auto& user : users)
257 {
258 const std::string& path =
259 static_cast<const std::string&>(user.first);
260 std::size_t lastIndex = path.rfind("/");
261 if (lastIndex == std::string::npos)
262 {
263 lastIndex = 0;
264 }
265 else
266 {
267 lastIndex += 1;
268 }
269 memberArray.push_back(
270 {{"@odata.id", "/redfish/v1/AccountService/Accounts/" +
271 path.substr(lastIndex)}});
272 }
273 },
274 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
275 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
276 }
Ed Tanous04ae99e2018-09-20 15:54:36 -0700277 void doPost(crow::Response& res, const crow::Request& req,
278 const std::vector<std::string>& params) override
279 {
280 auto asyncResp = std::make_shared<AsyncResp>(res);
281
Ed Tanous9712f8a2018-09-21 13:38:49 -0700282 std::string username;
283 std::string password;
Ed Tanousa24526d2018-12-10 15:17:59 -0800284 std::optional<std::string> roleId("User");
285 std::optional<bool> enabled = true;
Ed Tanous9712f8a2018-09-21 13:38:49 -0700286 if (!json_util::readJson(req, res, "UserName", username, "Password",
287 password, "RoleId", roleId, "Enabled",
288 enabled))
Ed Tanous04ae99e2018-09-20 15:54:36 -0700289 {
290 return;
291 }
292
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530293 std::string priv = getRoleIdFromPrivilege(*roleId);
294 if (priv.empty())
Ed Tanous04ae99e2018-09-20 15:54:36 -0700295 {
Jason M. Billsf12894f2018-10-09 12:45:45 -0700296 messages::propertyValueNotInList(asyncResp->res, *roleId, "RoleId");
Ed Tanous04ae99e2018-09-20 15:54:36 -0700297 return;
298 }
Ed Tanous9712f8a2018-09-21 13:38:49 -0700299 roleId = priv;
Ed Tanous04ae99e2018-09-20 15:54:36 -0700300
301 crow::connections::systemBus->async_method_call(
Ed Tanous9712f8a2018-09-21 13:38:49 -0700302 [asyncResp, username, password{std::move(password)}](
Ed Tanous04ae99e2018-09-20 15:54:36 -0700303 const boost::system::error_code ec) {
304 if (ec)
305 {
Jason M. Billsf12894f2018-10-09 12:45:45 -0700306 messages::resourceAlreadyExists(
307 asyncResp->res, "#ManagerAccount.v1_0_3.ManagerAccount",
308 "UserName", username);
Ed Tanous04ae99e2018-09-20 15:54:36 -0700309 return;
310 }
311
312 if (!pamUpdatePassword(username, password))
313 {
314 // At this point we have a user that's been created, but the
315 // password set failed. Something is wrong, so delete the
316 // user that we've already created
317 crow::connections::systemBus->async_method_call(
318 [asyncResp](const boost::system::error_code ec) {
319 if (ec)
320 {
Jason M. Billsf12894f2018-10-09 12:45:45 -0700321 messages::internalError(asyncResp->res);
Ed Tanous04ae99e2018-09-20 15:54:36 -0700322 return;
323 }
324
Jason M. Billsf12894f2018-10-09 12:45:45 -0700325 messages::invalidObject(asyncResp->res, "Password");
Ed Tanous04ae99e2018-09-20 15:54:36 -0700326 },
327 "xyz.openbmc_project.User.Manager",
328 "/xyz/openbmc_project/user/" + username,
329 "xyz.openbmc_project.Object.Delete", "Delete");
330
331 BMCWEB_LOG_ERROR << "pamUpdatePassword Failed";
332 return;
333 }
334
Jason M. Billsf12894f2018-10-09 12:45:45 -0700335 messages::created(asyncResp->res);
Ed Tanous04ae99e2018-09-20 15:54:36 -0700336 asyncResp->res.addHeader(
337 "Location",
338 "/redfish/v1/AccountService/Accounts/" + username);
339 },
340 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
Ed Tanous9712f8a2018-09-21 13:38:49 -0700341 "xyz.openbmc_project.User.Manager", "CreateUser", username,
Ed Tanous04ae99e2018-09-20 15:54:36 -0700342 std::array<const char*, 4>{"ipmi", "redfish", "ssh", "web"},
Ed Tanous9712f8a2018-09-21 13:38:49 -0700343 *roleId, *enabled);
Ed Tanous04ae99e2018-09-20 15:54:36 -0700344 }
Ed Tanousb9b2e0b2018-09-13 13:47:50 -0700345};
346
Ed Tanousa8408792018-09-05 16:08:38 -0700347template <typename Callback>
348inline void checkDbusPathExists(const std::string& path, Callback&& callback)
349{
350 using GetObjectType =
351 std::vector<std::pair<std::string, std::vector<std::string>>>;
352
353 crow::connections::systemBus->async_method_call(
354 [callback{std::move(callback)}](const boost::system::error_code ec,
355 const GetObjectType& object_names) {
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530356 callback(!ec && object_names.size() != 0);
Ed Tanousa8408792018-09-05 16:08:38 -0700357 },
358 "xyz.openbmc_project.ObjectMapper",
359 "/xyz/openbmc_project/object_mapper",
360 "xyz.openbmc_project.ObjectMapper", "GetObject", path,
361 std::array<std::string, 0>());
362}
363
Ed Tanousb9b2e0b2018-09-13 13:47:50 -0700364class ManagerAccount : public Node
365{
366 public:
367 ManagerAccount(CrowApp& app) :
368 Node(app, "/redfish/v1/AccountService/Accounts/<str>/", std::string())
369 {
Ed Tanousb9b2e0b2018-09-13 13:47:50 -0700370 entityPrivileges = {
371 {boost::beast::http::verb::get,
372 {{"ConfigureUsers"}, {"ConfigureManager"}, {"ConfigureSelf"}}},
373 {boost::beast::http::verb::head, {{"Login"}}},
374 {boost::beast::http::verb::patch, {{"ConfigureUsers"}}},
375 {boost::beast::http::verb::put, {{"ConfigureUsers"}}},
376 {boost::beast::http::verb::delete_, {{"ConfigureUsers"}}},
377 {boost::beast::http::verb::post, {{"ConfigureUsers"}}}};
378 }
379
380 private:
381 void doGet(crow::Response& res, const crow::Request& req,
382 const std::vector<std::string>& params) override
383 {
Ed Tanous0f74e642018-11-12 15:17:05 -0800384 res.jsonValue = {
385 {"@odata.context",
386 "/redfish/v1/$metadata#ManagerAccount.ManagerAccount"},
387 {"@odata.type", "#ManagerAccount.v1_0_3.ManagerAccount"},
Ed Tanous0f74e642018-11-12 15:17:05 -0800388 {"Name", "User Account"},
389 {"Description", "User Account"},
390 {"Password", nullptr},
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530391 {"RoleId", "Administrator"}};
Ed Tanous0f74e642018-11-12 15:17:05 -0800392
Ed Tanousb9b2e0b2018-09-13 13:47:50 -0700393 auto asyncResp = std::make_shared<AsyncResp>(res);
394
395 if (params.size() != 1)
396 {
Jason M. Billsf12894f2018-10-09 12:45:45 -0700397 messages::internalError(asyncResp->res);
Ed Tanousb9b2e0b2018-09-13 13:47:50 -0700398 return;
399 }
400
401 crow::connections::systemBus->async_method_call(
402 [asyncResp, accountName{std::string(params[0])}](
403 const boost::system::error_code ec,
404 const ManagedObjectType& users) {
405 if (ec)
406 {
Jason M. Billsf12894f2018-10-09 12:45:45 -0700407 messages::internalError(asyncResp->res);
Ed Tanousb9b2e0b2018-09-13 13:47:50 -0700408 return;
409 }
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530410 auto userIt = users.begin();
Ed Tanousb9b2e0b2018-09-13 13:47:50 -0700411
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530412 for (; userIt != users.end(); userIt++)
Ed Tanousb9b2e0b2018-09-13 13:47:50 -0700413 {
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530414 if (boost::ends_with(userIt->first.str, "/" + accountName))
Ed Tanousb9b2e0b2018-09-13 13:47:50 -0700415 {
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530416 break;
Ed Tanousb9b2e0b2018-09-13 13:47:50 -0700417 }
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530418 }
419 if (userIt == users.end())
420 {
421 messages::resourceNotFound(asyncResp->res, "ManagerAccount",
422 accountName);
423 return;
424 }
425 for (const auto& interface : userIt->second)
426 {
427 if (interface.first ==
428 "xyz.openbmc_project.User.Attributes")
Ed Tanousb9b2e0b2018-09-13 13:47:50 -0700429 {
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530430 for (const auto& property : interface.second)
Ed Tanous65b0dc32018-09-19 16:04:03 -0700431 {
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530432 if (property.first == "UserEnabled")
Ed Tanous65b0dc32018-09-19 16:04:03 -0700433 {
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530434 const bool* userEnabled =
Ed Tanousabf2add2019-01-22 16:40:12 -0800435 std::get_if<bool>(&property.second);
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530436 if (userEnabled == nullptr)
Ed Tanous65b0dc32018-09-19 16:04:03 -0700437 {
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530438 BMCWEB_LOG_ERROR
439 << "UserEnabled wasn't a bool";
440 messages::internalError(asyncResp->res);
441 return;
Ed Tanous65b0dc32018-09-19 16:04:03 -0700442 }
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530443 asyncResp->res.jsonValue["Enabled"] =
444 *userEnabled;
445 }
446 else if (property.first ==
447 "UserLockedForFailedAttempt")
448 {
449 const bool* userLocked =
Ed Tanousabf2add2019-01-22 16:40:12 -0800450 std::get_if<bool>(&property.second);
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530451 if (userLocked == nullptr)
452 {
453 BMCWEB_LOG_ERROR << "UserLockedForF"
454 "ailedAttempt "
455 "wasn't a bool";
456 messages::internalError(asyncResp->res);
457 return;
458 }
459 asyncResp->res.jsonValue["Locked"] =
460 *userLocked;
Ratan Gupta24c85422019-01-30 19:41:24 +0530461 asyncResp->res.jsonValue
462 ["Locked@Redfish.AllowableValues"] = {
463 false};
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530464 }
465 else if (property.first == "UserPrivilege")
466 {
467 const std::string* userRolePtr =
Ed Tanousabf2add2019-01-22 16:40:12 -0800468 std::get_if<std::string>(&property.second);
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530469 if (userRolePtr == nullptr)
470 {
471 BMCWEB_LOG_ERROR
472 << "UserPrivilege wasn't a "
473 "string";
474 messages::internalError(asyncResp->res);
475 return;
476 }
477 std::string priv =
478 getPrivilegeFromRoleId(*userRolePtr);
479 if (priv.empty())
480 {
481 BMCWEB_LOG_ERROR << "Invalid user role";
482 messages::internalError(asyncResp->res);
483 return;
484 }
485 asyncResp->res.jsonValue["RoleId"] = priv;
486
487 asyncResp->res.jsonValue["Links"]["Role"] = {
488 {"@odata.id", "/redfish/v1/AccountService/"
489 "Roles/" +
490 priv}};
Ed Tanous65b0dc32018-09-19 16:04:03 -0700491 }
492 }
Ed Tanousb9b2e0b2018-09-13 13:47:50 -0700493 }
494 }
495
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530496 asyncResp->res.jsonValue["@odata.id"] =
497 "/redfish/v1/AccountService/Accounts/" + accountName;
498 asyncResp->res.jsonValue["Id"] = accountName;
499 asyncResp->res.jsonValue["UserName"] = accountName;
Ed Tanousb9b2e0b2018-09-13 13:47:50 -0700500 },
501 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
502 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
503 }
Ed Tanousa8408792018-09-05 16:08:38 -0700504
505 void doPatch(crow::Response& res, const crow::Request& req,
506 const std::vector<std::string>& params) override
507 {
508 auto asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanousa8408792018-09-05 16:08:38 -0700509 if (params.size() != 1)
510 {
Jason M. Billsf12894f2018-10-09 12:45:45 -0700511 messages::internalError(asyncResp->res);
Ed Tanousa8408792018-09-05 16:08:38 -0700512 return;
513 }
514
Ed Tanousa24526d2018-12-10 15:17:59 -0800515 std::optional<std::string> newUserName;
516 std::optional<std::string> password;
517 std::optional<bool> enabled;
518 std::optional<std::string> roleId;
Ratan Gupta24c85422019-01-30 19:41:24 +0530519 std::optional<bool> locked;
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530520 if (!json_util::readJson(req, res, "UserName", newUserName, "Password",
Ratan Gupta24c85422019-01-30 19:41:24 +0530521 password, "RoleId", roleId, "Enabled", enabled,
522 "Locked", locked))
Ed Tanousa8408792018-09-05 16:08:38 -0700523 {
524 return;
525 }
526
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530527 const std::string& username = params[0];
Ed Tanousa8408792018-09-05 16:08:38 -0700528
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530529 if (!newUserName)
530 {
531 // If the username isn't being updated, we can update the properties
532 // directly
Ratan Gupta24c85422019-01-30 19:41:24 +0530533 updateUserProperties(asyncResp, username, password, enabled, roleId,
534 locked);
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530535 return;
536 }
537 else
538 {
539 crow::connections::systemBus->async_method_call(
540 [this, asyncResp, username, password(std::move(password)),
541 roleId(std::move(roleId)), enabled(std::move(enabled)),
Ratan Gupta24c85422019-01-30 19:41:24 +0530542 newUser{std::string(*newUserName)}, locked(std::move(locked))](
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530543 const boost::system::error_code ec) {
544 if (ec)
Ed Tanousa8408792018-09-05 16:08:38 -0700545 {
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530546 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
547 messages::resourceNotFound(
548 asyncResp->res,
549 "#ManagerAccount.v1_0_3.ManagerAccount", username);
550 return;
551 }
552
553 updateUserProperties(asyncResp, newUser, password, enabled,
Ratan Gupta24c85422019-01-30 19:41:24 +0530554 roleId, locked);
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530555 },
556 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
557 "xyz.openbmc_project.User.Manager", "RenameUser", username,
558 *newUserName);
559 }
560 }
561
562 void updateUserProperties(std::shared_ptr<AsyncResp> asyncResp,
563 const std::string& username,
Ed Tanousa24526d2018-12-10 15:17:59 -0800564 std::optional<std::string> password,
565 std::optional<bool> enabled,
Ratan Gupta24c85422019-01-30 19:41:24 +0530566 std::optional<std::string> roleId,
567 std::optional<bool> locked)
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530568 {
569 if (password)
570 {
571 if (!pamUpdatePassword(username, *password))
572 {
573 BMCWEB_LOG_ERROR << "pamUpdatePassword Failed";
574 messages::internalError(asyncResp->res);
575 return;
576 }
577 }
578
Ratan Gupta24c85422019-01-30 19:41:24 +0530579 std::string dbusObjectPath = "/xyz/openbmc_project/user/" + username;
580 dbus::utility::escapePathForDbus(dbusObjectPath);
581
582 checkDbusPathExists(
583 dbusObjectPath,
584 [dbusObjectPath(std::move(dbusObjectPath)), username,
585 password(std::move(password)), roleId(std::move(roleId)),
586 enabled(std::move(enabled)), locked(std::move(locked)),
587 asyncResp{std::move(asyncResp)}](int rc) {
588 if (!rc)
589 {
590 messages::invalidObject(asyncResp->res, username.c_str());
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530591 return;
Ratan Gupta24c85422019-01-30 19:41:24 +0530592 }
593 if (enabled)
594 {
595 crow::connections::systemBus->async_method_call(
596 [asyncResp](const boost::system::error_code ec) {
597 if (ec)
598 {
599 BMCWEB_LOG_ERROR << "D-Bus responses error: "
600 << ec;
601 messages::internalError(asyncResp->res);
602 return;
603 }
604 messages::success(asyncResp->res);
605 return;
606 },
607 "xyz.openbmc_project.User.Manager",
608 dbusObjectPath.c_str(),
609 "org.freedesktop.DBus.Properties", "Set",
610 "xyz.openbmc_project.User.Attributes", "UserEnabled",
611 std::variant<bool>{*enabled});
612 }
Ed Tanous9712f8a2018-09-21 13:38:49 -0700613
Ratan Gupta24c85422019-01-30 19:41:24 +0530614 if (roleId)
615 {
616 std::string priv = getRoleIdFromPrivilege(*roleId);
617 if (priv.empty())
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530618 {
Ratan Gupta24c85422019-01-30 19:41:24 +0530619 messages::propertyValueNotInList(asyncResp->res,
620 *roleId, "RoleId");
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530621 return;
622 }
Ratan Gupta24c85422019-01-30 19:41:24 +0530623
624 crow::connections::systemBus->async_method_call(
625 [asyncResp](const boost::system::error_code ec) {
626 if (ec)
627 {
628 BMCWEB_LOG_ERROR << "D-Bus responses error: "
629 << ec;
630 messages::internalError(asyncResp->res);
631 return;
632 }
633 messages::success(asyncResp->res);
634 },
635 "xyz.openbmc_project.User.Manager",
636 dbusObjectPath.c_str(),
637 "org.freedesktop.DBus.Properties", "Set",
638 "xyz.openbmc_project.User.Attributes", "UserPrivilege",
639 std::variant<std::string>{priv});
640 }
641
642 if (locked)
643 {
644 // admin can unlock the account which is locked by
645 // successive authentication failures but admin should not
646 // be allowed to lock an account.
647 if (*locked)
648 {
649 messages::propertyValueNotInList(asyncResp->res, "true",
650 "Locked");
651 return;
652 }
653
654 crow::connections::systemBus->async_method_call(
655 [asyncResp](const boost::system::error_code ec) {
656 if (ec)
657 {
658 BMCWEB_LOG_ERROR << "D-Bus responses error: "
659 << ec;
660 messages::internalError(asyncResp->res);
661 return;
662 }
663 messages::success(asyncResp->res);
664 return;
665 },
666 "xyz.openbmc_project.User.Manager",
667 dbusObjectPath.c_str(),
668 "org.freedesktop.DBus.Properties", "Set",
669 "xyz.openbmc_project.User.Attributes",
670 "UserLockedForFailedAttempt",
671 sdbusplus::message::variant<bool>{*locked});
672 }
673 });
Ed Tanousa8408792018-09-05 16:08:38 -0700674 }
Ed Tanous06e086d2018-09-19 17:19:52 -0700675
676 void doDelete(crow::Response& res, const crow::Request& req,
677 const std::vector<std::string>& params) override
678 {
679 auto asyncResp = std::make_shared<AsyncResp>(res);
680
681 if (params.size() != 1)
682 {
Jason M. Billsf12894f2018-10-09 12:45:45 -0700683 messages::internalError(asyncResp->res);
Ed Tanous06e086d2018-09-19 17:19:52 -0700684 return;
685 }
686
687 const std::string userPath = "/xyz/openbmc_project/user/" + params[0];
688
689 crow::connections::systemBus->async_method_call(
690 [asyncResp, username{std::move(params[0])}](
691 const boost::system::error_code ec) {
692 if (ec)
693 {
Jason M. Billsf12894f2018-10-09 12:45:45 -0700694 messages::resourceNotFound(
695 asyncResp->res, "#ManagerAccount.v1_0_3.ManagerAccount",
696 username);
Ed Tanous06e086d2018-09-19 17:19:52 -0700697 return;
698 }
699
Jason M. Billsf12894f2018-10-09 12:45:45 -0700700 messages::accountRemoved(asyncResp->res);
Ed Tanous06e086d2018-09-19 17:19:52 -0700701 },
702 "xyz.openbmc_project.User.Manager", userPath,
703 "xyz.openbmc_project.Object.Delete", "Delete");
704 }
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530705};
Lewanczyk, Dawid88d16c92018-02-02 14:51:09 +0100706
Ed Tanous1abe55e2018-09-05 08:30:59 -0700707} // namespace redfish