blob: a5c501d1b6874624456c03ccfb684472fedf26a9 [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};
Tanousf00032d2018-11-05 01:18:10 -0300227
Ed Tanousb9b2e0b2018-09-13 13:47:50 -0700228class AccountsCollection : public Node
229{
230 public:
231 AccountsCollection(CrowApp& app) :
232 Node(app, "/redfish/v1/AccountService/Accounts/")
233 {
Ed Tanousb9b2e0b2018-09-13 13:47:50 -0700234 entityPrivileges = {
235 {boost::beast::http::verb::get,
236 {{"ConfigureUsers"}, {"ConfigureManager"}}},
237 {boost::beast::http::verb::head, {{"Login"}}},
238 {boost::beast::http::verb::patch, {{"ConfigureUsers"}}},
239 {boost::beast::http::verb::put, {{"ConfigureUsers"}}},
240 {boost::beast::http::verb::delete_, {{"ConfigureUsers"}}},
241 {boost::beast::http::verb::post, {{"ConfigureUsers"}}}};
242 }
243
244 private:
245 void doGet(crow::Response& res, const crow::Request& req,
246 const std::vector<std::string>& params) override
247 {
Ed Tanousb9b2e0b2018-09-13 13:47:50 -0700248 auto asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous0f74e642018-11-12 15:17:05 -0800249 res.jsonValue = {{"@odata.context",
250 "/redfish/v1/"
251 "$metadata#ManagerAccountCollection."
252 "ManagerAccountCollection"},
253 {"@odata.id", "/redfish/v1/AccountService/Accounts"},
254 {"@odata.type", "#ManagerAccountCollection."
255 "ManagerAccountCollection"},
256 {"Name", "Accounts Collection"},
257 {"Description", "BMC User Accounts"}};
258
Ed Tanousb9b2e0b2018-09-13 13:47:50 -0700259 crow::connections::systemBus->async_method_call(
260 [asyncResp](const boost::system::error_code ec,
261 const ManagedObjectType& users) {
262 if (ec)
263 {
Jason M. Billsf12894f2018-10-09 12:45:45 -0700264 messages::internalError(asyncResp->res);
Ed Tanousb9b2e0b2018-09-13 13:47:50 -0700265 return;
266 }
267
268 nlohmann::json& memberArray =
269 asyncResp->res.jsonValue["Members"];
270 memberArray = nlohmann::json::array();
271
272 asyncResp->res.jsonValue["Members@odata.count"] = users.size();
273 for (auto& user : users)
274 {
275 const std::string& path =
276 static_cast<const std::string&>(user.first);
277 std::size_t lastIndex = path.rfind("/");
278 if (lastIndex == std::string::npos)
279 {
280 lastIndex = 0;
281 }
282 else
283 {
284 lastIndex += 1;
285 }
286 memberArray.push_back(
287 {{"@odata.id", "/redfish/v1/AccountService/Accounts/" +
288 path.substr(lastIndex)}});
289 }
290 },
291 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
292 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
293 }
Ed Tanous04ae99e2018-09-20 15:54:36 -0700294 void doPost(crow::Response& res, const crow::Request& req,
295 const std::vector<std::string>& params) override
296 {
297 auto asyncResp = std::make_shared<AsyncResp>(res);
298
Ed Tanous9712f8a2018-09-21 13:38:49 -0700299 std::string username;
300 std::string password;
Ed Tanousa24526d2018-12-10 15:17:59 -0800301 std::optional<std::string> roleId("User");
302 std::optional<bool> enabled = true;
Ed Tanous9712f8a2018-09-21 13:38:49 -0700303 if (!json_util::readJson(req, res, "UserName", username, "Password",
304 password, "RoleId", roleId, "Enabled",
305 enabled))
Ed Tanous04ae99e2018-09-20 15:54:36 -0700306 {
307 return;
308 }
309
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530310 std::string priv = getRoleIdFromPrivilege(*roleId);
311 if (priv.empty())
Ed Tanous04ae99e2018-09-20 15:54:36 -0700312 {
Jason M. Billsf12894f2018-10-09 12:45:45 -0700313 messages::propertyValueNotInList(asyncResp->res, *roleId, "RoleId");
Ed Tanous04ae99e2018-09-20 15:54:36 -0700314 return;
315 }
Ed Tanous9712f8a2018-09-21 13:38:49 -0700316 roleId = priv;
Ed Tanous04ae99e2018-09-20 15:54:36 -0700317
318 crow::connections::systemBus->async_method_call(
Ed Tanous9712f8a2018-09-21 13:38:49 -0700319 [asyncResp, username, password{std::move(password)}](
Ed Tanous04ae99e2018-09-20 15:54:36 -0700320 const boost::system::error_code ec) {
321 if (ec)
322 {
Jason M. Billsf12894f2018-10-09 12:45:45 -0700323 messages::resourceAlreadyExists(
324 asyncResp->res, "#ManagerAccount.v1_0_3.ManagerAccount",
325 "UserName", username);
Ed Tanous04ae99e2018-09-20 15:54:36 -0700326 return;
327 }
328
329 if (!pamUpdatePassword(username, password))
330 {
331 // At this point we have a user that's been created, but the
332 // password set failed. Something is wrong, so delete the
333 // user that we've already created
334 crow::connections::systemBus->async_method_call(
335 [asyncResp](const boost::system::error_code ec) {
336 if (ec)
337 {
Jason M. Billsf12894f2018-10-09 12:45:45 -0700338 messages::internalError(asyncResp->res);
Ed Tanous04ae99e2018-09-20 15:54:36 -0700339 return;
340 }
341
Jason M. Billsf12894f2018-10-09 12:45:45 -0700342 messages::invalidObject(asyncResp->res, "Password");
Ed Tanous04ae99e2018-09-20 15:54:36 -0700343 },
344 "xyz.openbmc_project.User.Manager",
345 "/xyz/openbmc_project/user/" + username,
346 "xyz.openbmc_project.Object.Delete", "Delete");
347
348 BMCWEB_LOG_ERROR << "pamUpdatePassword Failed";
349 return;
350 }
351
Jason M. Billsf12894f2018-10-09 12:45:45 -0700352 messages::created(asyncResp->res);
Ed Tanous04ae99e2018-09-20 15:54:36 -0700353 asyncResp->res.addHeader(
354 "Location",
355 "/redfish/v1/AccountService/Accounts/" + username);
356 },
357 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
Ed Tanous9712f8a2018-09-21 13:38:49 -0700358 "xyz.openbmc_project.User.Manager", "CreateUser", username,
Ed Tanous04ae99e2018-09-20 15:54:36 -0700359 std::array<const char*, 4>{"ipmi", "redfish", "ssh", "web"},
Ed Tanous9712f8a2018-09-21 13:38:49 -0700360 *roleId, *enabled);
Ed Tanous04ae99e2018-09-20 15:54:36 -0700361 }
Ed Tanousb9b2e0b2018-09-13 13:47:50 -0700362};
363
Ed Tanousa8408792018-09-05 16:08:38 -0700364template <typename Callback>
365inline void checkDbusPathExists(const std::string& path, Callback&& callback)
366{
367 using GetObjectType =
368 std::vector<std::pair<std::string, std::vector<std::string>>>;
369
370 crow::connections::systemBus->async_method_call(
371 [callback{std::move(callback)}](const boost::system::error_code ec,
372 const GetObjectType& object_names) {
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530373 callback(!ec && object_names.size() != 0);
Ed Tanousa8408792018-09-05 16:08:38 -0700374 },
375 "xyz.openbmc_project.ObjectMapper",
376 "/xyz/openbmc_project/object_mapper",
377 "xyz.openbmc_project.ObjectMapper", "GetObject", path,
378 std::array<std::string, 0>());
379}
380
Ed Tanousb9b2e0b2018-09-13 13:47:50 -0700381class ManagerAccount : public Node
382{
383 public:
384 ManagerAccount(CrowApp& app) :
385 Node(app, "/redfish/v1/AccountService/Accounts/<str>/", std::string())
386 {
Ed Tanousb9b2e0b2018-09-13 13:47:50 -0700387 entityPrivileges = {
388 {boost::beast::http::verb::get,
389 {{"ConfigureUsers"}, {"ConfigureManager"}, {"ConfigureSelf"}}},
390 {boost::beast::http::verb::head, {{"Login"}}},
391 {boost::beast::http::verb::patch, {{"ConfigureUsers"}}},
392 {boost::beast::http::verb::put, {{"ConfigureUsers"}}},
393 {boost::beast::http::verb::delete_, {{"ConfigureUsers"}}},
394 {boost::beast::http::verb::post, {{"ConfigureUsers"}}}};
395 }
396
397 private:
398 void doGet(crow::Response& res, const crow::Request& req,
399 const std::vector<std::string>& params) override
400 {
Ed Tanous0f74e642018-11-12 15:17:05 -0800401 res.jsonValue = {
402 {"@odata.context",
403 "/redfish/v1/$metadata#ManagerAccount.ManagerAccount"},
404 {"@odata.type", "#ManagerAccount.v1_0_3.ManagerAccount"},
Ed Tanous0f74e642018-11-12 15:17:05 -0800405 {"Name", "User Account"},
406 {"Description", "User Account"},
407 {"Password", nullptr},
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530408 {"RoleId", "Administrator"}};
Ed Tanous0f74e642018-11-12 15:17:05 -0800409
Ed Tanousb9b2e0b2018-09-13 13:47:50 -0700410 auto asyncResp = std::make_shared<AsyncResp>(res);
411
412 if (params.size() != 1)
413 {
Jason M. Billsf12894f2018-10-09 12:45:45 -0700414 messages::internalError(asyncResp->res);
Ed Tanousb9b2e0b2018-09-13 13:47:50 -0700415 return;
416 }
417
418 crow::connections::systemBus->async_method_call(
419 [asyncResp, accountName{std::string(params[0])}](
420 const boost::system::error_code ec,
421 const ManagedObjectType& users) {
422 if (ec)
423 {
Jason M. Billsf12894f2018-10-09 12:45:45 -0700424 messages::internalError(asyncResp->res);
Ed Tanousb9b2e0b2018-09-13 13:47:50 -0700425 return;
426 }
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530427 auto userIt = users.begin();
Ed Tanousb9b2e0b2018-09-13 13:47:50 -0700428
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530429 for (; userIt != users.end(); userIt++)
Ed Tanousb9b2e0b2018-09-13 13:47:50 -0700430 {
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530431 if (boost::ends_with(userIt->first.str, "/" + accountName))
Ed Tanousb9b2e0b2018-09-13 13:47:50 -0700432 {
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530433 break;
Ed Tanousb9b2e0b2018-09-13 13:47:50 -0700434 }
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530435 }
436 if (userIt == users.end())
437 {
438 messages::resourceNotFound(asyncResp->res, "ManagerAccount",
439 accountName);
440 return;
441 }
442 for (const auto& interface : userIt->second)
443 {
444 if (interface.first ==
445 "xyz.openbmc_project.User.Attributes")
Ed Tanousb9b2e0b2018-09-13 13:47:50 -0700446 {
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530447 for (const auto& property : interface.second)
Ed Tanous65b0dc32018-09-19 16:04:03 -0700448 {
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530449 if (property.first == "UserEnabled")
Ed Tanous65b0dc32018-09-19 16:04:03 -0700450 {
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530451 const bool* userEnabled =
Ed Tanousabf2add2019-01-22 16:40:12 -0800452 std::get_if<bool>(&property.second);
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530453 if (userEnabled == nullptr)
Ed Tanous65b0dc32018-09-19 16:04:03 -0700454 {
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530455 BMCWEB_LOG_ERROR
456 << "UserEnabled wasn't a bool";
457 messages::internalError(asyncResp->res);
458 return;
Ed Tanous65b0dc32018-09-19 16:04:03 -0700459 }
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530460 asyncResp->res.jsonValue["Enabled"] =
461 *userEnabled;
462 }
463 else if (property.first ==
464 "UserLockedForFailedAttempt")
465 {
466 const bool* userLocked =
Ed Tanousabf2add2019-01-22 16:40:12 -0800467 std::get_if<bool>(&property.second);
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530468 if (userLocked == nullptr)
469 {
470 BMCWEB_LOG_ERROR << "UserLockedForF"
471 "ailedAttempt "
472 "wasn't a bool";
473 messages::internalError(asyncResp->res);
474 return;
475 }
476 asyncResp->res.jsonValue["Locked"] =
477 *userLocked;
Ratan Gupta24c85422019-01-30 19:41:24 +0530478 asyncResp->res.jsonValue
479 ["Locked@Redfish.AllowableValues"] = {
480 false};
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530481 }
482 else if (property.first == "UserPrivilege")
483 {
484 const std::string* userRolePtr =
Ed Tanousabf2add2019-01-22 16:40:12 -0800485 std::get_if<std::string>(&property.second);
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530486 if (userRolePtr == nullptr)
487 {
488 BMCWEB_LOG_ERROR
489 << "UserPrivilege wasn't a "
490 "string";
491 messages::internalError(asyncResp->res);
492 return;
493 }
494 std::string priv =
495 getPrivilegeFromRoleId(*userRolePtr);
496 if (priv.empty())
497 {
498 BMCWEB_LOG_ERROR << "Invalid user role";
499 messages::internalError(asyncResp->res);
500 return;
501 }
502 asyncResp->res.jsonValue["RoleId"] = priv;
503
504 asyncResp->res.jsonValue["Links"]["Role"] = {
505 {"@odata.id", "/redfish/v1/AccountService/"
506 "Roles/" +
507 priv}};
Ed Tanous65b0dc32018-09-19 16:04:03 -0700508 }
509 }
Ed Tanousb9b2e0b2018-09-13 13:47:50 -0700510 }
511 }
512
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530513 asyncResp->res.jsonValue["@odata.id"] =
514 "/redfish/v1/AccountService/Accounts/" + accountName;
515 asyncResp->res.jsonValue["Id"] = accountName;
516 asyncResp->res.jsonValue["UserName"] = accountName;
Ed Tanousb9b2e0b2018-09-13 13:47:50 -0700517 },
518 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
519 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
520 }
Ed Tanousa8408792018-09-05 16:08:38 -0700521
522 void doPatch(crow::Response& res, const crow::Request& req,
523 const std::vector<std::string>& params) override
524 {
525 auto asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanousa8408792018-09-05 16:08:38 -0700526 if (params.size() != 1)
527 {
Jason M. Billsf12894f2018-10-09 12:45:45 -0700528 messages::internalError(asyncResp->res);
Ed Tanousa8408792018-09-05 16:08:38 -0700529 return;
530 }
531
Ed Tanousa24526d2018-12-10 15:17:59 -0800532 std::optional<std::string> newUserName;
533 std::optional<std::string> password;
534 std::optional<bool> enabled;
535 std::optional<std::string> roleId;
Ratan Gupta24c85422019-01-30 19:41:24 +0530536 std::optional<bool> locked;
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530537 if (!json_util::readJson(req, res, "UserName", newUserName, "Password",
Ratan Gupta24c85422019-01-30 19:41:24 +0530538 password, "RoleId", roleId, "Enabled", enabled,
539 "Locked", locked))
Ed Tanousa8408792018-09-05 16:08:38 -0700540 {
541 return;
542 }
543
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530544 const std::string& username = params[0];
Ed Tanousa8408792018-09-05 16:08:38 -0700545
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530546 if (!newUserName)
547 {
548 // If the username isn't being updated, we can update the properties
549 // directly
Ratan Gupta24c85422019-01-30 19:41:24 +0530550 updateUserProperties(asyncResp, username, password, enabled, roleId,
551 locked);
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530552 return;
553 }
554 else
555 {
556 crow::connections::systemBus->async_method_call(
557 [this, asyncResp, username, password(std::move(password)),
558 roleId(std::move(roleId)), enabled(std::move(enabled)),
Ratan Gupta24c85422019-01-30 19:41:24 +0530559 newUser{std::string(*newUserName)}, locked(std::move(locked))](
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530560 const boost::system::error_code ec) {
561 if (ec)
Ed Tanousa8408792018-09-05 16:08:38 -0700562 {
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530563 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
564 messages::resourceNotFound(
565 asyncResp->res,
566 "#ManagerAccount.v1_0_3.ManagerAccount", username);
567 return;
568 }
569
570 updateUserProperties(asyncResp, newUser, password, enabled,
Ratan Gupta24c85422019-01-30 19:41:24 +0530571 roleId, locked);
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530572 },
573 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
574 "xyz.openbmc_project.User.Manager", "RenameUser", username,
575 *newUserName);
576 }
577 }
578
579 void updateUserProperties(std::shared_ptr<AsyncResp> asyncResp,
580 const std::string& username,
Ed Tanousa24526d2018-12-10 15:17:59 -0800581 std::optional<std::string> password,
582 std::optional<bool> enabled,
Ratan Gupta24c85422019-01-30 19:41:24 +0530583 std::optional<std::string> roleId,
584 std::optional<bool> locked)
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530585 {
586 if (password)
587 {
588 if (!pamUpdatePassword(username, *password))
589 {
590 BMCWEB_LOG_ERROR << "pamUpdatePassword Failed";
591 messages::internalError(asyncResp->res);
592 return;
593 }
594 }
595
Ratan Gupta24c85422019-01-30 19:41:24 +0530596 std::string dbusObjectPath = "/xyz/openbmc_project/user/" + username;
597 dbus::utility::escapePathForDbus(dbusObjectPath);
598
599 checkDbusPathExists(
600 dbusObjectPath,
601 [dbusObjectPath(std::move(dbusObjectPath)), username,
602 password(std::move(password)), roleId(std::move(roleId)),
603 enabled(std::move(enabled)), locked(std::move(locked)),
604 asyncResp{std::move(asyncResp)}](int rc) {
605 if (!rc)
606 {
607 messages::invalidObject(asyncResp->res, username.c_str());
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530608 return;
Ratan Gupta24c85422019-01-30 19:41:24 +0530609 }
610 if (enabled)
611 {
612 crow::connections::systemBus->async_method_call(
613 [asyncResp](const boost::system::error_code ec) {
614 if (ec)
615 {
616 BMCWEB_LOG_ERROR << "D-Bus responses error: "
617 << ec;
618 messages::internalError(asyncResp->res);
619 return;
620 }
621 messages::success(asyncResp->res);
622 return;
623 },
624 "xyz.openbmc_project.User.Manager",
625 dbusObjectPath.c_str(),
626 "org.freedesktop.DBus.Properties", "Set",
627 "xyz.openbmc_project.User.Attributes", "UserEnabled",
628 std::variant<bool>{*enabled});
629 }
Ed Tanous9712f8a2018-09-21 13:38:49 -0700630
Ratan Gupta24c85422019-01-30 19:41:24 +0530631 if (roleId)
632 {
633 std::string priv = getRoleIdFromPrivilege(*roleId);
634 if (priv.empty())
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530635 {
Ratan Gupta24c85422019-01-30 19:41:24 +0530636 messages::propertyValueNotInList(asyncResp->res,
637 *roleId, "RoleId");
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530638 return;
639 }
Ratan Gupta24c85422019-01-30 19:41:24 +0530640
641 crow::connections::systemBus->async_method_call(
642 [asyncResp](const boost::system::error_code ec) {
643 if (ec)
644 {
645 BMCWEB_LOG_ERROR << "D-Bus responses error: "
646 << ec;
647 messages::internalError(asyncResp->res);
648 return;
649 }
650 messages::success(asyncResp->res);
651 },
652 "xyz.openbmc_project.User.Manager",
653 dbusObjectPath.c_str(),
654 "org.freedesktop.DBus.Properties", "Set",
655 "xyz.openbmc_project.User.Attributes", "UserPrivilege",
656 std::variant<std::string>{priv});
657 }
658
659 if (locked)
660 {
661 // admin can unlock the account which is locked by
662 // successive authentication failures but admin should not
663 // be allowed to lock an account.
664 if (*locked)
665 {
666 messages::propertyValueNotInList(asyncResp->res, "true",
667 "Locked");
668 return;
669 }
670
671 crow::connections::systemBus->async_method_call(
672 [asyncResp](const boost::system::error_code ec) {
673 if (ec)
674 {
675 BMCWEB_LOG_ERROR << "D-Bus responses error: "
676 << ec;
677 messages::internalError(asyncResp->res);
678 return;
679 }
680 messages::success(asyncResp->res);
681 return;
682 },
683 "xyz.openbmc_project.User.Manager",
684 dbusObjectPath.c_str(),
685 "org.freedesktop.DBus.Properties", "Set",
686 "xyz.openbmc_project.User.Attributes",
687 "UserLockedForFailedAttempt",
688 sdbusplus::message::variant<bool>{*locked});
689 }
690 });
Ed Tanousa8408792018-09-05 16:08:38 -0700691 }
Ed Tanous06e086d2018-09-19 17:19:52 -0700692
693 void doDelete(crow::Response& res, const crow::Request& req,
694 const std::vector<std::string>& params) override
695 {
696 auto asyncResp = std::make_shared<AsyncResp>(res);
697
698 if (params.size() != 1)
699 {
Jason M. Billsf12894f2018-10-09 12:45:45 -0700700 messages::internalError(asyncResp->res);
Ed Tanous06e086d2018-09-19 17:19:52 -0700701 return;
702 }
703
704 const std::string userPath = "/xyz/openbmc_project/user/" + params[0];
705
706 crow::connections::systemBus->async_method_call(
707 [asyncResp, username{std::move(params[0])}](
708 const boost::system::error_code ec) {
709 if (ec)
710 {
Jason M. Billsf12894f2018-10-09 12:45:45 -0700711 messages::resourceNotFound(
712 asyncResp->res, "#ManagerAccount.v1_0_3.ManagerAccount",
713 username);
Ed Tanous06e086d2018-09-19 17:19:52 -0700714 return;
715 }
716
Jason M. Billsf12894f2018-10-09 12:45:45 -0700717 messages::accountRemoved(asyncResp->res);
Ed Tanous06e086d2018-09-19 17:19:52 -0700718 },
719 "xyz.openbmc_project.User.Manager", userPath,
720 "xyz.openbmc_project.Object.Delete", "Delete");
721 }
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530722};
Lewanczyk, Dawid88d16c92018-02-02 14:51:09 +0100723
Ed Tanous1abe55e2018-09-05 08:30:59 -0700724} // namespace redfish