blob: 9365ebb06f2c7dd0df096df5208e5cbaca4993b7 [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},
AppaRao Puli343ff2e2019-03-24 00:42:13 +0530105 {"MaxPasswordLength", 20},
AppaRao Puli3d958bb2018-12-25 12:45:54 +0530106 {"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;
Ratan Gupta19fb6e72019-03-04 13:30:50 +0530170 std::optional<uint16_t> minPasswordLength;
171 std::optional<uint16_t> maxPasswordLength;
172
AppaRao Puli3d958bb2018-12-25 12:45:54 +0530173 if (!json_util::readJson(req, res, "AccountLockoutDuration",
174 unlockTimeout, "AccountLockoutThreshold",
Ratan Gupta19fb6e72019-03-04 13:30:50 +0530175 lockoutThreshold, "MaxPasswordLength",
176 maxPasswordLength, "MinPasswordLength",
177 minPasswordLength))
AppaRao Puli3d958bb2018-12-25 12:45:54 +0530178 {
179 return;
180 }
Ratan Gupta19fb6e72019-03-04 13:30:50 +0530181
182 if (minPasswordLength)
183 {
184 messages::propertyNotWritable(asyncResp->res, "MinPasswordLength");
185 }
186
187 if (maxPasswordLength)
188 {
189 messages::propertyNotWritable(asyncResp->res, "MaxPasswordLength");
190 }
191
AppaRao Puli3d958bb2018-12-25 12:45:54 +0530192 if (unlockTimeout)
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",
Ed Tanousabf2add2019-01-22 16:40:12 -0800206 "AccountUnlockTimeout", std::variant<uint32_t>(*unlockTimeout));
AppaRao Puli3d958bb2018-12-25 12:45:54 +0530207 }
208 if (lockoutThreshold)
209 {
210 crow::connections::systemBus->async_method_call(
211 [asyncResp](const boost::system::error_code ec) {
212 if (ec)
213 {
214 messages::internalError(asyncResp->res);
215 return;
216 }
Ratan Guptaadd61332019-02-13 20:49:16 +0530217 messages::success(asyncResp->res);
AppaRao Puli3d958bb2018-12-25 12:45:54 +0530218 },
219 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
220 "org.freedesktop.DBus.Properties", "Set",
221 "xyz.openbmc_project.User.AccountPolicy",
222 "MaxLoginAttemptBeforeLockout",
Ed Tanousabf2add2019-01-22 16:40:12 -0800223 std::variant<uint16_t>(*lockoutThreshold));
AppaRao Puli3d958bb2018-12-25 12:45:54 +0530224 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700225 }
Lewanczyk, Dawid88d16c92018-02-02 14:51:09 +0100226};
Ed Tanousb9b2e0b2018-09-13 13:47:50 -0700227class AccountsCollection : public Node
228{
229 public:
230 AccountsCollection(CrowApp& app) :
231 Node(app, "/redfish/v1/AccountService/Accounts/")
232 {
Ed Tanousb9b2e0b2018-09-13 13:47:50 -0700233 entityPrivileges = {
234 {boost::beast::http::verb::get,
235 {{"ConfigureUsers"}, {"ConfigureManager"}}},
236 {boost::beast::http::verb::head, {{"Login"}}},
237 {boost::beast::http::verb::patch, {{"ConfigureUsers"}}},
238 {boost::beast::http::verb::put, {{"ConfigureUsers"}}},
239 {boost::beast::http::verb::delete_, {{"ConfigureUsers"}}},
240 {boost::beast::http::verb::post, {{"ConfigureUsers"}}}};
241 }
242
243 private:
244 void doGet(crow::Response& res, const crow::Request& req,
245 const std::vector<std::string>& params) override
246 {
Ed Tanousb9b2e0b2018-09-13 13:47:50 -0700247 auto asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous0f74e642018-11-12 15:17:05 -0800248 res.jsonValue = {{"@odata.context",
249 "/redfish/v1/"
250 "$metadata#ManagerAccountCollection."
251 "ManagerAccountCollection"},
252 {"@odata.id", "/redfish/v1/AccountService/Accounts"},
253 {"@odata.type", "#ManagerAccountCollection."
254 "ManagerAccountCollection"},
255 {"Name", "Accounts Collection"},
256 {"Description", "BMC User Accounts"}};
257
Ed Tanousb9b2e0b2018-09-13 13:47:50 -0700258 crow::connections::systemBus->async_method_call(
259 [asyncResp](const boost::system::error_code ec,
260 const ManagedObjectType& users) {
261 if (ec)
262 {
Jason M. Billsf12894f2018-10-09 12:45:45 -0700263 messages::internalError(asyncResp->res);
Ed Tanousb9b2e0b2018-09-13 13:47:50 -0700264 return;
265 }
266
267 nlohmann::json& memberArray =
268 asyncResp->res.jsonValue["Members"];
269 memberArray = nlohmann::json::array();
270
271 asyncResp->res.jsonValue["Members@odata.count"] = users.size();
272 for (auto& user : users)
273 {
274 const std::string& path =
275 static_cast<const std::string&>(user.first);
276 std::size_t lastIndex = path.rfind("/");
277 if (lastIndex == std::string::npos)
278 {
279 lastIndex = 0;
280 }
281 else
282 {
283 lastIndex += 1;
284 }
285 memberArray.push_back(
286 {{"@odata.id", "/redfish/v1/AccountService/Accounts/" +
287 path.substr(lastIndex)}});
288 }
289 },
290 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
291 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
292 }
Ed Tanous04ae99e2018-09-20 15:54:36 -0700293 void doPost(crow::Response& res, const crow::Request& req,
294 const std::vector<std::string>& params) override
295 {
296 auto asyncResp = std::make_shared<AsyncResp>(res);
297
Ed Tanous9712f8a2018-09-21 13:38:49 -0700298 std::string username;
299 std::string password;
Ed Tanousa24526d2018-12-10 15:17:59 -0800300 std::optional<std::string> roleId("User");
301 std::optional<bool> enabled = true;
Ed Tanous9712f8a2018-09-21 13:38:49 -0700302 if (!json_util::readJson(req, res, "UserName", username, "Password",
303 password, "RoleId", roleId, "Enabled",
304 enabled))
Ed Tanous04ae99e2018-09-20 15:54:36 -0700305 {
306 return;
307 }
308
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530309 std::string priv = getRoleIdFromPrivilege(*roleId);
310 if (priv.empty())
Ed Tanous04ae99e2018-09-20 15:54:36 -0700311 {
Jason M. Billsf12894f2018-10-09 12:45:45 -0700312 messages::propertyValueNotInList(asyncResp->res, *roleId, "RoleId");
Ed Tanous04ae99e2018-09-20 15:54:36 -0700313 return;
314 }
Ed Tanous9712f8a2018-09-21 13:38:49 -0700315 roleId = priv;
Ed Tanous04ae99e2018-09-20 15:54:36 -0700316
317 crow::connections::systemBus->async_method_call(
Ed Tanous9712f8a2018-09-21 13:38:49 -0700318 [asyncResp, username, password{std::move(password)}](
Ed Tanous04ae99e2018-09-20 15:54:36 -0700319 const boost::system::error_code ec) {
320 if (ec)
321 {
Jason M. Billsf12894f2018-10-09 12:45:45 -0700322 messages::resourceAlreadyExists(
323 asyncResp->res, "#ManagerAccount.v1_0_3.ManagerAccount",
324 "UserName", username);
Ed Tanous04ae99e2018-09-20 15:54:36 -0700325 return;
326 }
327
328 if (!pamUpdatePassword(username, password))
329 {
330 // At this point we have a user that's been created, but the
331 // password set failed. Something is wrong, so delete the
332 // user that we've already created
333 crow::connections::systemBus->async_method_call(
334 [asyncResp](const boost::system::error_code ec) {
335 if (ec)
336 {
Jason M. Billsf12894f2018-10-09 12:45:45 -0700337 messages::internalError(asyncResp->res);
Ed Tanous04ae99e2018-09-20 15:54:36 -0700338 return;
339 }
340
Jason M. Billsf12894f2018-10-09 12:45:45 -0700341 messages::invalidObject(asyncResp->res, "Password");
Ed Tanous04ae99e2018-09-20 15:54:36 -0700342 },
343 "xyz.openbmc_project.User.Manager",
344 "/xyz/openbmc_project/user/" + username,
345 "xyz.openbmc_project.Object.Delete", "Delete");
346
347 BMCWEB_LOG_ERROR << "pamUpdatePassword Failed";
348 return;
349 }
350
Jason M. Billsf12894f2018-10-09 12:45:45 -0700351 messages::created(asyncResp->res);
Ed Tanous04ae99e2018-09-20 15:54:36 -0700352 asyncResp->res.addHeader(
353 "Location",
354 "/redfish/v1/AccountService/Accounts/" + username);
355 },
356 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
Ed Tanous9712f8a2018-09-21 13:38:49 -0700357 "xyz.openbmc_project.User.Manager", "CreateUser", username,
Ed Tanous04ae99e2018-09-20 15:54:36 -0700358 std::array<const char*, 4>{"ipmi", "redfish", "ssh", "web"},
Ed Tanous9712f8a2018-09-21 13:38:49 -0700359 *roleId, *enabled);
Ed Tanous04ae99e2018-09-20 15:54:36 -0700360 }
Ed Tanousb9b2e0b2018-09-13 13:47:50 -0700361};
362
Ed Tanousa8408792018-09-05 16:08:38 -0700363template <typename Callback>
364inline void checkDbusPathExists(const std::string& path, Callback&& callback)
365{
366 using GetObjectType =
367 std::vector<std::pair<std::string, std::vector<std::string>>>;
368
369 crow::connections::systemBus->async_method_call(
370 [callback{std::move(callback)}](const boost::system::error_code ec,
371 const GetObjectType& object_names) {
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530372 callback(!ec && object_names.size() != 0);
Ed Tanousa8408792018-09-05 16:08:38 -0700373 },
374 "xyz.openbmc_project.ObjectMapper",
375 "/xyz/openbmc_project/object_mapper",
376 "xyz.openbmc_project.ObjectMapper", "GetObject", path,
377 std::array<std::string, 0>());
378}
379
Ed Tanousb9b2e0b2018-09-13 13:47:50 -0700380class ManagerAccount : public Node
381{
382 public:
383 ManagerAccount(CrowApp& app) :
384 Node(app, "/redfish/v1/AccountService/Accounts/<str>/", std::string())
385 {
Ed Tanousb9b2e0b2018-09-13 13:47:50 -0700386 entityPrivileges = {
387 {boost::beast::http::verb::get,
388 {{"ConfigureUsers"}, {"ConfigureManager"}, {"ConfigureSelf"}}},
389 {boost::beast::http::verb::head, {{"Login"}}},
390 {boost::beast::http::verb::patch, {{"ConfigureUsers"}}},
391 {boost::beast::http::verb::put, {{"ConfigureUsers"}}},
392 {boost::beast::http::verb::delete_, {{"ConfigureUsers"}}},
393 {boost::beast::http::verb::post, {{"ConfigureUsers"}}}};
394 }
395
396 private:
397 void doGet(crow::Response& res, const crow::Request& req,
398 const std::vector<std::string>& params) override
399 {
Ed Tanous0f74e642018-11-12 15:17:05 -0800400 res.jsonValue = {
401 {"@odata.context",
402 "/redfish/v1/$metadata#ManagerAccount.ManagerAccount"},
403 {"@odata.type", "#ManagerAccount.v1_0_3.ManagerAccount"},
Ed Tanous0f74e642018-11-12 15:17:05 -0800404 {"Name", "User Account"},
405 {"Description", "User Account"},
406 {"Password", nullptr},
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530407 {"RoleId", "Administrator"}};
Ed Tanous0f74e642018-11-12 15:17:05 -0800408
Ed Tanousb9b2e0b2018-09-13 13:47:50 -0700409 auto asyncResp = std::make_shared<AsyncResp>(res);
410
411 if (params.size() != 1)
412 {
Jason M. Billsf12894f2018-10-09 12:45:45 -0700413 messages::internalError(asyncResp->res);
Ed Tanousb9b2e0b2018-09-13 13:47:50 -0700414 return;
415 }
416
417 crow::connections::systemBus->async_method_call(
418 [asyncResp, accountName{std::string(params[0])}](
419 const boost::system::error_code ec,
420 const ManagedObjectType& users) {
421 if (ec)
422 {
Jason M. Billsf12894f2018-10-09 12:45:45 -0700423 messages::internalError(asyncResp->res);
Ed Tanousb9b2e0b2018-09-13 13:47:50 -0700424 return;
425 }
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530426 auto userIt = users.begin();
Ed Tanousb9b2e0b2018-09-13 13:47:50 -0700427
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530428 for (; userIt != users.end(); userIt++)
Ed Tanousb9b2e0b2018-09-13 13:47:50 -0700429 {
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530430 if (boost::ends_with(userIt->first.str, "/" + accountName))
Ed Tanousb9b2e0b2018-09-13 13:47:50 -0700431 {
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530432 break;
Ed Tanousb9b2e0b2018-09-13 13:47:50 -0700433 }
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530434 }
435 if (userIt == users.end())
436 {
437 messages::resourceNotFound(asyncResp->res, "ManagerAccount",
438 accountName);
439 return;
440 }
441 for (const auto& interface : userIt->second)
442 {
443 if (interface.first ==
444 "xyz.openbmc_project.User.Attributes")
Ed Tanousb9b2e0b2018-09-13 13:47:50 -0700445 {
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530446 for (const auto& property : interface.second)
Ed Tanous65b0dc32018-09-19 16:04:03 -0700447 {
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530448 if (property.first == "UserEnabled")
Ed Tanous65b0dc32018-09-19 16:04:03 -0700449 {
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530450 const bool* userEnabled =
Ed Tanousabf2add2019-01-22 16:40:12 -0800451 std::get_if<bool>(&property.second);
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530452 if (userEnabled == nullptr)
Ed Tanous65b0dc32018-09-19 16:04:03 -0700453 {
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530454 BMCWEB_LOG_ERROR
455 << "UserEnabled wasn't a bool";
456 messages::internalError(asyncResp->res);
457 return;
Ed Tanous65b0dc32018-09-19 16:04:03 -0700458 }
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530459 asyncResp->res.jsonValue["Enabled"] =
460 *userEnabled;
461 }
462 else if (property.first ==
463 "UserLockedForFailedAttempt")
464 {
465 const bool* userLocked =
Ed Tanousabf2add2019-01-22 16:40:12 -0800466 std::get_if<bool>(&property.second);
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530467 if (userLocked == nullptr)
468 {
469 BMCWEB_LOG_ERROR << "UserLockedForF"
470 "ailedAttempt "
471 "wasn't a bool";
472 messages::internalError(asyncResp->res);
473 return;
474 }
475 asyncResp->res.jsonValue["Locked"] =
476 *userLocked;
Ratan Gupta24c85422019-01-30 19:41:24 +0530477 asyncResp->res.jsonValue
478 ["Locked@Redfish.AllowableValues"] = {
479 false};
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530480 }
481 else if (property.first == "UserPrivilege")
482 {
483 const std::string* userRolePtr =
Ed Tanousabf2add2019-01-22 16:40:12 -0800484 std::get_if<std::string>(&property.second);
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530485 if (userRolePtr == nullptr)
486 {
487 BMCWEB_LOG_ERROR
488 << "UserPrivilege wasn't a "
489 "string";
490 messages::internalError(asyncResp->res);
491 return;
492 }
493 std::string priv =
494 getPrivilegeFromRoleId(*userRolePtr);
495 if (priv.empty())
496 {
497 BMCWEB_LOG_ERROR << "Invalid user role";
498 messages::internalError(asyncResp->res);
499 return;
500 }
501 asyncResp->res.jsonValue["RoleId"] = priv;
502
503 asyncResp->res.jsonValue["Links"]["Role"] = {
504 {"@odata.id", "/redfish/v1/AccountService/"
505 "Roles/" +
506 priv}};
Ed Tanous65b0dc32018-09-19 16:04:03 -0700507 }
508 }
Ed Tanousb9b2e0b2018-09-13 13:47:50 -0700509 }
510 }
511
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530512 asyncResp->res.jsonValue["@odata.id"] =
513 "/redfish/v1/AccountService/Accounts/" + accountName;
514 asyncResp->res.jsonValue["Id"] = accountName;
515 asyncResp->res.jsonValue["UserName"] = accountName;
Ed Tanousb9b2e0b2018-09-13 13:47:50 -0700516 },
517 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
518 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
519 }
Ed Tanousa8408792018-09-05 16:08:38 -0700520
521 void doPatch(crow::Response& res, const crow::Request& req,
522 const std::vector<std::string>& params) override
523 {
524 auto asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanousa8408792018-09-05 16:08:38 -0700525 if (params.size() != 1)
526 {
Jason M. Billsf12894f2018-10-09 12:45:45 -0700527 messages::internalError(asyncResp->res);
Ed Tanousa8408792018-09-05 16:08:38 -0700528 return;
529 }
530
Ed Tanousa24526d2018-12-10 15:17:59 -0800531 std::optional<std::string> newUserName;
532 std::optional<std::string> password;
533 std::optional<bool> enabled;
534 std::optional<std::string> roleId;
Ratan Gupta24c85422019-01-30 19:41:24 +0530535 std::optional<bool> locked;
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530536 if (!json_util::readJson(req, res, "UserName", newUserName, "Password",
Ratan Gupta24c85422019-01-30 19:41:24 +0530537 password, "RoleId", roleId, "Enabled", enabled,
538 "Locked", locked))
Ed Tanousa8408792018-09-05 16:08:38 -0700539 {
540 return;
541 }
542
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530543 const std::string& username = params[0];
Ed Tanousa8408792018-09-05 16:08:38 -0700544
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530545 if (!newUserName)
546 {
547 // If the username isn't being updated, we can update the properties
548 // directly
Ratan Gupta24c85422019-01-30 19:41:24 +0530549 updateUserProperties(asyncResp, username, password, enabled, roleId,
550 locked);
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530551 return;
552 }
553 else
554 {
555 crow::connections::systemBus->async_method_call(
556 [this, asyncResp, username, password(std::move(password)),
557 roleId(std::move(roleId)), enabled(std::move(enabled)),
Ratan Gupta24c85422019-01-30 19:41:24 +0530558 newUser{std::string(*newUserName)}, locked(std::move(locked))](
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530559 const boost::system::error_code ec) {
560 if (ec)
Ed Tanousa8408792018-09-05 16:08:38 -0700561 {
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530562 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
563 messages::resourceNotFound(
564 asyncResp->res,
565 "#ManagerAccount.v1_0_3.ManagerAccount", username);
566 return;
567 }
568
569 updateUserProperties(asyncResp, newUser, password, enabled,
Ratan Gupta24c85422019-01-30 19:41:24 +0530570 roleId, locked);
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530571 },
572 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
573 "xyz.openbmc_project.User.Manager", "RenameUser", username,
574 *newUserName);
575 }
576 }
577
578 void updateUserProperties(std::shared_ptr<AsyncResp> asyncResp,
579 const std::string& username,
Ed Tanousa24526d2018-12-10 15:17:59 -0800580 std::optional<std::string> password,
581 std::optional<bool> enabled,
Ratan Gupta24c85422019-01-30 19:41:24 +0530582 std::optional<std::string> roleId,
583 std::optional<bool> locked)
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530584 {
585 if (password)
586 {
587 if (!pamUpdatePassword(username, *password))
588 {
589 BMCWEB_LOG_ERROR << "pamUpdatePassword Failed";
590 messages::internalError(asyncResp->res);
591 return;
592 }
593 }
594
Ratan Gupta24c85422019-01-30 19:41:24 +0530595 std::string dbusObjectPath = "/xyz/openbmc_project/user/" + username;
596 dbus::utility::escapePathForDbus(dbusObjectPath);
597
598 checkDbusPathExists(
599 dbusObjectPath,
600 [dbusObjectPath(std::move(dbusObjectPath)), username,
601 password(std::move(password)), roleId(std::move(roleId)),
602 enabled(std::move(enabled)), locked(std::move(locked)),
603 asyncResp{std::move(asyncResp)}](int rc) {
604 if (!rc)
605 {
606 messages::invalidObject(asyncResp->res, username.c_str());
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530607 return;
Ratan Gupta24c85422019-01-30 19:41:24 +0530608 }
609 if (enabled)
610 {
611 crow::connections::systemBus->async_method_call(
612 [asyncResp](const boost::system::error_code ec) {
613 if (ec)
614 {
615 BMCWEB_LOG_ERROR << "D-Bus responses error: "
616 << ec;
617 messages::internalError(asyncResp->res);
618 return;
619 }
620 messages::success(asyncResp->res);
621 return;
622 },
623 "xyz.openbmc_project.User.Manager",
624 dbusObjectPath.c_str(),
625 "org.freedesktop.DBus.Properties", "Set",
626 "xyz.openbmc_project.User.Attributes", "UserEnabled",
627 std::variant<bool>{*enabled});
628 }
Ed Tanous9712f8a2018-09-21 13:38:49 -0700629
Ratan Gupta24c85422019-01-30 19:41:24 +0530630 if (roleId)
631 {
632 std::string priv = getRoleIdFromPrivilege(*roleId);
633 if (priv.empty())
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530634 {
Ratan Gupta24c85422019-01-30 19:41:24 +0530635 messages::propertyValueNotInList(asyncResp->res,
636 *roleId, "RoleId");
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530637 return;
638 }
Ratan Gupta24c85422019-01-30 19:41:24 +0530639
640 crow::connections::systemBus->async_method_call(
641 [asyncResp](const boost::system::error_code ec) {
642 if (ec)
643 {
644 BMCWEB_LOG_ERROR << "D-Bus responses error: "
645 << ec;
646 messages::internalError(asyncResp->res);
647 return;
648 }
649 messages::success(asyncResp->res);
650 },
651 "xyz.openbmc_project.User.Manager",
652 dbusObjectPath.c_str(),
653 "org.freedesktop.DBus.Properties", "Set",
654 "xyz.openbmc_project.User.Attributes", "UserPrivilege",
655 std::variant<std::string>{priv});
656 }
657
658 if (locked)
659 {
660 // admin can unlock the account which is locked by
661 // successive authentication failures but admin should not
662 // be allowed to lock an account.
663 if (*locked)
664 {
665 messages::propertyValueNotInList(asyncResp->res, "true",
666 "Locked");
667 return;
668 }
669
670 crow::connections::systemBus->async_method_call(
671 [asyncResp](const boost::system::error_code ec) {
672 if (ec)
673 {
674 BMCWEB_LOG_ERROR << "D-Bus responses error: "
675 << ec;
676 messages::internalError(asyncResp->res);
677 return;
678 }
679 messages::success(asyncResp->res);
680 return;
681 },
682 "xyz.openbmc_project.User.Manager",
683 dbusObjectPath.c_str(),
684 "org.freedesktop.DBus.Properties", "Set",
685 "xyz.openbmc_project.User.Attributes",
686 "UserLockedForFailedAttempt",
687 sdbusplus::message::variant<bool>{*locked});
688 }
689 });
Ed Tanousa8408792018-09-05 16:08:38 -0700690 }
Ed Tanous06e086d2018-09-19 17:19:52 -0700691
692 void doDelete(crow::Response& res, const crow::Request& req,
693 const std::vector<std::string>& params) override
694 {
695 auto asyncResp = std::make_shared<AsyncResp>(res);
696
697 if (params.size() != 1)
698 {
Jason M. Billsf12894f2018-10-09 12:45:45 -0700699 messages::internalError(asyncResp->res);
Ed Tanous06e086d2018-09-19 17:19:52 -0700700 return;
701 }
702
703 const std::string userPath = "/xyz/openbmc_project/user/" + params[0];
704
705 crow::connections::systemBus->async_method_call(
706 [asyncResp, username{std::move(params[0])}](
707 const boost::system::error_code ec) {
708 if (ec)
709 {
Jason M. Billsf12894f2018-10-09 12:45:45 -0700710 messages::resourceNotFound(
711 asyncResp->res, "#ManagerAccount.v1_0_3.ManagerAccount",
712 username);
Ed Tanous06e086d2018-09-19 17:19:52 -0700713 return;
714 }
715
Jason M. Billsf12894f2018-10-09 12:45:45 -0700716 messages::accountRemoved(asyncResp->res);
Ed Tanous06e086d2018-09-19 17:19:52 -0700717 },
718 "xyz.openbmc_project.User.Manager", userPath,
719 "xyz.openbmc_project.Object.Delete", "Delete");
720 }
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530721};
Lewanczyk, Dawid88d16c92018-02-02 14:51:09 +0100722
Ed Tanous1abe55e2018-09-05 08:30:59 -0700723} // namespace redfish