blob: a183f6867b95265d10d1a15d7c82089cf4874240 [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
Ratan Gupta6973a582018-12-13 18:25:44 +053028constexpr const char* ldapConfigObject =
29 "/xyz/openbmc_project/user/ldap/openldap";
Ratan Guptaab828d72019-04-22 14:18:33 +053030constexpr const char* ADConfigObject =
31 "/xyz/openbmc_project/user/ldap/active_directory";
32
Ratan Gupta6973a582018-12-13 18:25:44 +053033constexpr const char* ldapRootObject = "/xyz/openbmc_project/user/ldap";
34constexpr const char* ldapDbusService = "xyz.openbmc_project.Ldap.Config";
35constexpr const char* ldapConfigInterface =
36 "xyz.openbmc_project.User.Ldap.Config";
37constexpr const char* ldapCreateInterface =
38 "xyz.openbmc_project.User.Ldap.Create";
39constexpr const char* ldapEnableInterface = "xyz.openbmc_project.Object.Enable";
Ratan Gupta06785242019-07-26 22:30:16 +053040constexpr const char* ldapPrivMapperInterface =
41 "xyz.openbmc_project.User.PrivilegeMapper";
Ratan Gupta6973a582018-12-13 18:25:44 +053042constexpr const char* dbusObjManagerIntf = "org.freedesktop.DBus.ObjectManager";
43constexpr const char* propertyInterface = "org.freedesktop.DBus.Properties";
44constexpr const char* mapperBusName = "xyz.openbmc_project.ObjectMapper";
45constexpr const char* mapperObjectPath = "/xyz/openbmc_project/object_mapper";
46constexpr const char* mapperIntf = "xyz.openbmc_project.ObjectMapper";
47
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -060048struct LDAPRoleMapData
49{
50 std::string groupName;
51 std::string privilege;
52};
53
Ratan Gupta6973a582018-12-13 18:25:44 +053054struct LDAPConfigData
55{
56 std::string uri{};
57 std::string bindDN{};
58 std::string baseDN{};
59 std::string searchScope{};
60 std::string serverType{};
61 bool serviceEnabled = false;
62 std::string userNameAttribute{};
63 std::string groupAttribute{};
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -060064 std::vector<std::pair<std::string, LDAPRoleMapData>> groupRoleList;
Ratan Gupta6973a582018-12-13 18:25:44 +053065};
66
Ed Tanousb9b2e0b2018-09-13 13:47:50 -070067using ManagedObjectType = std::vector<std::pair<
68 sdbusplus::message::object_path,
69 boost::container::flat_map<
Ed Tanousabf2add2019-01-22 16:40:12 -080070 std::string, boost::container::flat_map<
71 std::string, std::variant<bool, std::string>>>>>;
Ratan Gupta6973a582018-12-13 18:25:44 +053072using GetObjectType =
73 std::vector<std::pair<std::string, std::vector<std::string>>>;
AppaRao Puli84e12cb2018-10-11 01:28:15 +053074
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -060075inline std::string getRoleIdFromPrivilege(std::string_view role)
AppaRao Puli84e12cb2018-10-11 01:28:15 +053076{
77 if (role == "priv-admin")
78 {
79 return "Administrator";
80 }
81 else if (role == "priv-callback")
82 {
83 return "Callback";
84 }
85 else if (role == "priv-user")
86 {
87 return "User";
88 }
89 else if (role == "priv-operator")
90 {
91 return "Operator";
92 }
93 return "";
94}
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -060095inline std::string getPrivilegeFromRoleId(std::string_view role)
AppaRao Puli84e12cb2018-10-11 01:28:15 +053096{
97 if (role == "Administrator")
98 {
99 return "priv-admin";
100 }
101 else if (role == "Callback")
102 {
103 return "priv-callback";
104 }
105 else if (role == "User")
106 {
107 return "priv-user";
108 }
109 else if (role == "Operator")
110 {
111 return "priv-operator";
112 }
113 return "";
114}
Ed Tanousb9b2e0b2018-09-13 13:47:50 -0700115
Ratan Gupta6973a582018-12-13 18:25:44 +0530116void parseLDAPConfigData(nlohmann::json& json_response,
Ratan Guptaab828d72019-04-22 14:18:33 +0530117 const LDAPConfigData& confData,
118 const std::string& ldapType)
Ratan Gupta6973a582018-12-13 18:25:44 +0530119{
Ratan Guptaab828d72019-04-22 14:18:33 +0530120 std::string service =
121 (ldapType == "LDAP") ? "LDAPService" : "ActiveDirectoryService";
Marri Devender Rao37cce912019-02-20 01:05:22 -0600122 nlohmann::json ldap = {
Ratan Gupta6973a582018-12-13 18:25:44 +0530123 {"AccountProviderType", service},
Ratan Gupta6973a582018-12-13 18:25:44 +0530124 {"ServiceEnabled", confData.serviceEnabled},
125 {"ServiceAddresses", nlohmann::json::array({confData.uri})},
126 {"Authentication",
127 {{"AuthenticationType", "UsernameAndPassword"},
Ratan Gupta6973a582018-12-13 18:25:44 +0530128 {"Username", confData.bindDN},
129 {"Password", nullptr}}},
130 {"LDAPService",
131 {{"SearchSettings",
132 {{"BaseDistinguishedNames",
133 nlohmann::json::array({confData.baseDN})},
134 {"UsernameAttribute", confData.userNameAttribute},
135 {"GroupsAttribute", confData.groupAttribute}}}}},
136 };
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600137
Marri Devender Rao37cce912019-02-20 01:05:22 -0600138 json_response[ldapType].update(std::move(ldap));
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600139
140 nlohmann::json& roleMapArray = json_response[ldapType]["RemoteRoleMapping"];
141 roleMapArray = nlohmann::json::array();
142 for (auto& obj : confData.groupRoleList)
143 {
144 BMCWEB_LOG_DEBUG << "Pushing the data groupName="
145 << obj.second.groupName << "\n";
146 roleMapArray.push_back(
147 {nlohmann::json::array({"RemoteGroup", obj.second.groupName}),
148 nlohmann::json::array(
149 {"LocalRole", getRoleIdFromPrivilege(obj.second.privilege)})});
150 }
Ratan Gupta6973a582018-12-13 18:25:44 +0530151}
152
153/**
Ratan Gupta06785242019-07-26 22:30:16 +0530154 * @brief validates given JSON input and then calls appropriate method to
155 * create, to delete or to set Rolemapping object based on the given input.
156 *
157 */
158static void handleRoleMapPatch(
159 const std::shared_ptr<AsyncResp>& asyncResp,
160 const std::vector<std::pair<std::string, LDAPRoleMapData>>& roleMapObjData,
161 const std::string& serverType, std::vector<nlohmann::json>& input)
162{
163 for (size_t index = 0; index < input.size(); index++)
164 {
165 nlohmann::json& thisJson = input[index];
166
167 if (thisJson.is_null())
168 {
169 // delete the existing object
170 if (index < roleMapObjData.size())
171 {
172 crow::connections::systemBus->async_method_call(
173 [asyncResp, roleMapObjData, serverType,
174 index](const boost::system::error_code ec) {
175 if (ec)
176 {
177 BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
178 messages::internalError(asyncResp->res);
179 return;
180 }
181 asyncResp->res
182 .jsonValue[serverType]["RemoteRoleMapping"][index] =
183 nullptr;
184 },
185 ldapDbusService, roleMapObjData[index].first,
186 "xyz.openbmc_project.Object.Delete", "Delete");
187 }
188 else
189 {
190 BMCWEB_LOG_ERROR << "Can't delete the object";
191 messages::propertyValueTypeError(
192 asyncResp->res, thisJson.dump(),
193 "RemoteRoleMapping/" + std::to_string(index));
194 return;
195 }
196 }
197 else if (thisJson.empty())
198 {
199 // Don't do anything for the empty objects,parse next json
200 // eg {"RemoteRoleMapping",[{}]}
201 }
202 else
203 {
204 // update/create the object
205 std::optional<std::string> remoteGroup;
206 std::optional<std::string> localRole;
207
208 if (!json_util::readJson(thisJson, asyncResp->res, "RemoteGroup",
209 remoteGroup, "LocalRole", localRole))
210 {
211 continue;
212 }
213
214 // Update existing RoleMapping Object
215 if (index < roleMapObjData.size())
216 {
217 BMCWEB_LOG_DEBUG << "Update Role Map Object";
218 // If "RemoteGroup" info is provided
219 if (remoteGroup)
220 {
221 crow::connections::systemBus->async_method_call(
222 [asyncResp, roleMapObjData, serverType, index,
223 remoteGroup](const boost::system::error_code ec) {
224 if (ec)
225 {
226 BMCWEB_LOG_ERROR << "DBUS response error: "
227 << ec;
228 messages::internalError(asyncResp->res);
229 return;
230 }
231 asyncResp->res
232 .jsonValue[serverType]["RemoteRoleMapping"]
233 [index]["RemoteGroup"] = *remoteGroup;
234 },
235 ldapDbusService, roleMapObjData[index].first,
236 propertyInterface, "Set",
237 "xyz.openbmc_project.User.PrivilegeMapperEntry",
238 "GroupName",
239 std::variant<std::string>(std::move(*remoteGroup)));
240 }
241
242 // If "LocalRole" info is provided
243 if (localRole)
244 {
245 crow::connections::systemBus->async_method_call(
246 [asyncResp, roleMapObjData, serverType, index,
247 localRole](const boost::system::error_code ec) {
248 if (ec)
249 {
250 BMCWEB_LOG_ERROR << "DBUS response error: "
251 << ec;
252 messages::internalError(asyncResp->res);
253 return;
254 }
255 asyncResp->res
256 .jsonValue[serverType]["RemoteRoleMapping"]
257 [index]["LocalRole"] = *localRole;
258 },
259 ldapDbusService, roleMapObjData[index].first,
260 propertyInterface, "Set",
261 "xyz.openbmc_project.User.PrivilegeMapperEntry",
262 "Privilege",
263 std::variant<std::string>(
264 getPrivilegeFromRoleId(std::move(*localRole))));
265 }
266 }
267 // Create a new RoleMapping Object.
268 else
269 {
270 BMCWEB_LOG_DEBUG
271 << "setRoleMappingProperties: Creating new Object";
272 std::string pathString =
273 "RemoteRoleMapping/" + std::to_string(index);
274
275 if (!localRole)
276 {
277 messages::propertyMissing(asyncResp->res,
278 pathString + "/LocalRole");
279 continue;
280 }
281 if (!remoteGroup)
282 {
283 messages::propertyMissing(asyncResp->res,
284 pathString + "/RemoteGroup");
285 continue;
286 }
287
288 std::string dbusObjectPath;
289 if (serverType == "ActiveDirectory")
290 {
291 dbusObjectPath = ADConfigObject;
292 }
293 else if (serverType == "LDAP")
294 {
295 dbusObjectPath = ldapConfigObject;
296 }
297
298 BMCWEB_LOG_DEBUG << "Remote Group=" << *remoteGroup
299 << ",LocalRole=" << *localRole;
300
301 crow::connections::systemBus->async_method_call(
Ed Tanous271584a2019-07-09 16:24:22 -0700302 [asyncResp, serverType, localRole,
Ratan Gupta06785242019-07-26 22:30:16 +0530303 remoteGroup](const boost::system::error_code ec) {
304 if (ec)
305 {
306 BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
307 messages::internalError(asyncResp->res);
308 return;
309 }
310 nlohmann::json& remoteRoleJson =
311 asyncResp->res
312 .jsonValue[serverType]["RemoteRoleMapping"];
313 remoteRoleJson.push_back(
314 {{"LocalRole", *localRole},
315 {"RemoteGroup", *remoteGroup}});
316 },
317 ldapDbusService, dbusObjectPath, ldapPrivMapperInterface,
318 "Create", std::move(*remoteGroup),
319 getPrivilegeFromRoleId(std::move(*localRole)));
320 }
321 }
322 }
323}
324
325/**
Ratan Gupta6973a582018-12-13 18:25:44 +0530326 * Function that retrieves all properties for LDAP config object
327 * into JSON
328 */
329template <typename CallbackFunc>
330inline void getLDAPConfigData(const std::string& ldapType,
331 CallbackFunc&& callback)
332{
Ratan Guptaab828d72019-04-22 14:18:33 +0530333
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600334 const std::array<const char*, 2> interfaces = {ldapEnableInterface,
Ratan Gupta6973a582018-12-13 18:25:44 +0530335 ldapConfigInterface};
336
337 crow::connections::systemBus->async_method_call(
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600338 [callback, ldapType](const boost::system::error_code ec,
339 const GetObjectType& resp) {
340 LDAPConfigData confData{};
341 if (ec || resp.empty())
342 {
343 BMCWEB_LOG_ERROR << "DBUS response error during getting of "
344 "service name: "
345 << ec;
346 callback(false, confData, ldapType);
347 return;
348 }
349 std::string service = resp.begin()->first;
350 crow::connections::systemBus->async_method_call(
351 [callback, ldapType](const boost::system::error_code error_code,
352 const ManagedObjectType& ldapObjects) {
353 LDAPConfigData confData{};
354 if (error_code)
355 {
356 callback(false, confData, ldapType);
357 BMCWEB_LOG_ERROR << "D-Bus responses error: "
358 << error_code;
359 return;
360 }
361
362 std::string ldapDbusType;
363 std::string searchString;
364
365 if (ldapType == "LDAP")
366 {
367 ldapDbusType = "xyz.openbmc_project.User.Ldap.Config."
368 "Type.OpenLdap";
369 searchString = "openldap";
370 }
371 else if (ldapType == "ActiveDirectory")
372 {
373 ldapDbusType =
374 "xyz.openbmc_project.User.Ldap.Config.Type."
375 "ActiveDirectory";
376 searchString = "active_directory";
377 }
378 else
379 {
380 BMCWEB_LOG_ERROR
381 << "Can't get the DbusType for the given type="
382 << ldapType;
383 callback(false, confData, ldapType);
384 return;
385 }
386
387 std::string ldapEnableInterfaceStr = ldapEnableInterface;
388 std::string ldapConfigInterfaceStr = ldapConfigInterface;
389
390 for (const auto& object : ldapObjects)
391 {
392 // let's find the object whose ldap type is equal to the
393 // given type
394 if (object.first.str.find(searchString) ==
395 std::string::npos)
396 {
397 continue;
398 }
399
400 for (const auto& interface : object.second)
401 {
402 if (interface.first == ldapEnableInterfaceStr)
403 {
404 // rest of the properties are string.
405 for (const auto& property : interface.second)
406 {
407 if (property.first == "Enabled")
408 {
409 const bool* value =
410 std::get_if<bool>(&property.second);
411 if (value == nullptr)
412 {
413 continue;
414 }
415 confData.serviceEnabled = *value;
416 break;
417 }
418 }
419 }
420 else if (interface.first == ldapConfigInterfaceStr)
421 {
422
423 for (const auto& property : interface.second)
424 {
Ed Tanous271584a2019-07-09 16:24:22 -0700425 const std::string* strValue =
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600426 std::get_if<std::string>(
427 &property.second);
Ed Tanous271584a2019-07-09 16:24:22 -0700428 if (strValue == nullptr)
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600429 {
430 continue;
431 }
432 if (property.first == "LDAPServerURI")
433 {
Ed Tanous271584a2019-07-09 16:24:22 -0700434 confData.uri = *strValue;
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600435 }
436 else if (property.first == "LDAPBindDN")
437 {
Ed Tanous271584a2019-07-09 16:24:22 -0700438 confData.bindDN = *strValue;
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600439 }
440 else if (property.first == "LDAPBaseDN")
441 {
Ed Tanous271584a2019-07-09 16:24:22 -0700442 confData.baseDN = *strValue;
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600443 }
444 else if (property.first ==
445 "LDAPSearchScope")
446 {
Ed Tanous271584a2019-07-09 16:24:22 -0700447 confData.searchScope = *strValue;
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600448 }
449 else if (property.first ==
450 "GroupNameAttribute")
451 {
Ed Tanous271584a2019-07-09 16:24:22 -0700452 confData.groupAttribute = *strValue;
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600453 }
454 else if (property.first ==
455 "UserNameAttribute")
456 {
Ed Tanous271584a2019-07-09 16:24:22 -0700457 confData.userNameAttribute = *strValue;
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600458 }
459 else if (property.first == "LDAPType")
460 {
Ed Tanous271584a2019-07-09 16:24:22 -0700461 confData.serverType = *strValue;
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600462 }
463 }
464 }
465 else if (interface.first ==
466 "xyz.openbmc_project.User."
467 "PrivilegeMapperEntry")
468 {
469 LDAPRoleMapData roleMapData{};
470 for (const auto& property : interface.second)
471 {
Ed Tanous271584a2019-07-09 16:24:22 -0700472 const std::string* strValue =
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600473 std::get_if<std::string>(
474 &property.second);
475
Ed Tanous271584a2019-07-09 16:24:22 -0700476 if (strValue == nullptr)
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600477 {
478 continue;
479 }
480
481 if (property.first == "GroupName")
482 {
Ed Tanous271584a2019-07-09 16:24:22 -0700483 roleMapData.groupName = *strValue;
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600484 }
485 else if (property.first == "Privilege")
486 {
Ed Tanous271584a2019-07-09 16:24:22 -0700487 roleMapData.privilege = *strValue;
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600488 }
489 }
490
491 confData.groupRoleList.push_back(std::make_pair(
492 object.first.str, roleMapData));
493 }
494 }
495 }
496 callback(true, confData, ldapType);
497 },
498 service, ldapRootObject, dbusObjManagerIntf,
499 "GetManagedObjects");
500 },
501 mapperBusName, mapperObjectPath, mapperIntf, "GetObject",
502 ldapConfigObject, interfaces);
Ratan Gupta6973a582018-12-13 18:25:44 +0530503}
504
Ed Tanous1abe55e2018-09-05 08:30:59 -0700505class AccountService : public Node
506{
507 public:
508 AccountService(CrowApp& app) : Node(app, "/redfish/v1/AccountService/")
509 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700510 entityPrivileges = {
511 {boost::beast::http::verb::get,
512 {{"ConfigureUsers"}, {"ConfigureManager"}}},
513 {boost::beast::http::verb::head, {{"Login"}}},
514 {boost::beast::http::verb::patch, {{"ConfigureUsers"}}},
515 {boost::beast::http::verb::put, {{"ConfigureUsers"}}},
516 {boost::beast::http::verb::delete_, {{"ConfigureUsers"}}},
517 {boost::beast::http::verb::post, {{"ConfigureUsers"}}}};
518 }
Lewanczyk, Dawid88d16c92018-02-02 14:51:09 +0100519
Ed Tanous1abe55e2018-09-05 08:30:59 -0700520 private:
Ratan Gupta8a07d282019-03-16 08:33:47 +0530521 /**
522 * @brief parses the authentication section under the LDAP
523 * @param input JSON data
524 * @param asyncResp pointer to the JSON response
525 * @param userName userName to be filled from the given JSON.
526 * @param password password to be filled from the given JSON.
527 */
528 void
529 parseLDAPAuthenticationJson(nlohmann::json input,
530 const std::shared_ptr<AsyncResp>& asyncResp,
531 std::optional<std::string>& username,
532 std::optional<std::string>& password)
533 {
534 std::optional<std::string> authType;
535
536 if (!json_util::readJson(input, asyncResp->res, "AuthenticationType",
537 authType, "Username", username, "Password",
538 password))
539 {
540 return;
541 }
542 if (!authType)
543 {
544 return;
545 }
546 if (*authType != "UsernameAndPassword")
547 {
548 messages::propertyValueNotInList(asyncResp->res, *authType,
549 "AuthenticationType");
550 return;
551 }
552 }
553 /**
554 * @brief parses the LDAPService section under the LDAP
555 * @param input JSON data
556 * @param asyncResp pointer to the JSON response
557 * @param baseDNList baseDN to be filled from the given JSON.
558 * @param userNameAttribute userName to be filled from the given JSON.
559 * @param groupaAttribute password to be filled from the given JSON.
560 */
561
562 void parseLDAPServiceJson(
563 nlohmann::json input, const std::shared_ptr<AsyncResp>& asyncResp,
564 std::optional<std::vector<std::string>>& baseDNList,
565 std::optional<std::string>& userNameAttribute,
566 std::optional<std::string>& groupsAttribute)
567 {
568 std::optional<nlohmann::json> searchSettings;
569
570 if (!json_util::readJson(input, asyncResp->res, "SearchSettings",
571 searchSettings))
572 {
573 return;
574 }
575 if (!searchSettings)
576 {
577 return;
578 }
579 if (!json_util::readJson(*searchSettings, asyncResp->res,
580 "BaseDistinguishedNames", baseDNList,
581 "UsernameAttribute", userNameAttribute,
582 "GroupsAttribute", groupsAttribute))
583 {
584 return;
585 }
586 }
587 /**
588 * @brief updates the LDAP server address and updates the
589 json response with the new value.
590 * @param serviceAddressList address to be updated.
591 * @param asyncResp pointer to the JSON response
592 * @param ldapServerElementName Type of LDAP
593 server(openLDAP/ActiveDirectory)
594 */
595
596 void handleServiceAddressPatch(
597 const std::vector<std::string>& serviceAddressList,
598 const std::shared_ptr<AsyncResp>& asyncResp,
599 const std::string& ldapServerElementName,
600 const std::string& ldapConfigObject)
601 {
602 crow::connections::systemBus->async_method_call(
603 [asyncResp, ldapServerElementName,
604 serviceAddressList](const boost::system::error_code ec) {
605 if (ec)
606 {
607 BMCWEB_LOG_DEBUG
608 << "Error Occured in updating the service address";
609 messages::internalError(asyncResp->res);
610 return;
611 }
612 std::vector<std::string> modifiedserviceAddressList = {
613 serviceAddressList.front()};
614 asyncResp->res
615 .jsonValue[ldapServerElementName]["ServiceAddresses"] =
616 modifiedserviceAddressList;
617 if ((serviceAddressList).size() > 1)
618 {
619 messages::propertyValueModified(asyncResp->res,
620 "ServiceAddresses",
621 serviceAddressList.front());
622 }
623 BMCWEB_LOG_DEBUG << "Updated the service address";
624 },
625 ldapDbusService, ldapConfigObject, propertyInterface, "Set",
626 ldapConfigInterface, "LDAPServerURI",
627 std::variant<std::string>(serviceAddressList.front()));
628 }
629 /**
630 * @brief updates the LDAP Bind DN and updates the
631 json response with the new value.
632 * @param username name of the user which needs to be updated.
633 * @param asyncResp pointer to the JSON response
634 * @param ldapServerElementName Type of LDAP
635 server(openLDAP/ActiveDirectory)
636 */
637
638 void handleUserNamePatch(const std::string& username,
639 const std::shared_ptr<AsyncResp>& asyncResp,
640 const std::string& ldapServerElementName,
641 const std::string& ldapConfigObject)
642 {
643 crow::connections::systemBus->async_method_call(
644 [asyncResp, username,
645 ldapServerElementName](const boost::system::error_code ec) {
646 if (ec)
647 {
648 BMCWEB_LOG_DEBUG
649 << "Error occured in updating the username";
650 messages::internalError(asyncResp->res);
651 return;
652 }
653 asyncResp->res.jsonValue[ldapServerElementName]
654 ["Authentication"]["Username"] =
655 username;
656 BMCWEB_LOG_DEBUG << "Updated the username";
657 },
658 ldapDbusService, ldapConfigObject, propertyInterface, "Set",
659 ldapConfigInterface, "LDAPBindDN",
660 std::variant<std::string>(username));
661 }
662
663 /**
664 * @brief updates the LDAP password
665 * @param password : ldap password which needs to be updated.
666 * @param asyncResp pointer to the JSON response
667 * @param ldapServerElementName Type of LDAP
668 * server(openLDAP/ActiveDirectory)
669 */
670
671 void handlePasswordPatch(const std::string& password,
672 const std::shared_ptr<AsyncResp>& asyncResp,
673 const std::string& ldapServerElementName,
674 const std::string& ldapConfigObject)
675 {
676 crow::connections::systemBus->async_method_call(
677 [asyncResp, password,
678 ldapServerElementName](const boost::system::error_code ec) {
679 if (ec)
680 {
681 BMCWEB_LOG_DEBUG
682 << "Error occured in updating the password";
683 messages::internalError(asyncResp->res);
684 return;
685 }
686 asyncResp->res.jsonValue[ldapServerElementName]
687 ["Authentication"]["Password"] = "";
688 BMCWEB_LOG_DEBUG << "Updated the password";
689 },
690 ldapDbusService, ldapConfigObject, propertyInterface, "Set",
691 ldapConfigInterface, "LDAPBindDNPassword",
692 std::variant<std::string>(password));
693 }
694
695 /**
696 * @brief updates the LDAP BaseDN and updates the
697 json response with the new value.
698 * @param baseDNList baseDN list which needs to be updated.
699 * @param asyncResp pointer to the JSON response
700 * @param ldapServerElementName Type of LDAP
701 server(openLDAP/ActiveDirectory)
702 */
703
704 void handleBaseDNPatch(const std::vector<std::string>& baseDNList,
705 const std::shared_ptr<AsyncResp>& asyncResp,
706 const std::string& ldapServerElementName,
707 const std::string& ldapConfigObject)
708 {
709 crow::connections::systemBus->async_method_call(
710 [asyncResp, baseDNList,
711 ldapServerElementName](const boost::system::error_code ec) {
712 if (ec)
713 {
714 BMCWEB_LOG_DEBUG << "Error Occured in Updating the base DN";
715 messages::internalError(asyncResp->res);
716 return;
717 }
718 auto& serverTypeJson =
719 asyncResp->res.jsonValue[ldapServerElementName];
720 auto& searchSettingsJson =
721 serverTypeJson["LDAPService"]["SearchSettings"];
722 std::vector<std::string> modifiedBaseDNList = {
723 baseDNList.front()};
724 searchSettingsJson["BaseDistinguishedNames"] =
725 modifiedBaseDNList;
726 if (baseDNList.size() > 1)
727 {
728 messages::propertyValueModified(asyncResp->res,
729 "BaseDistinguishedNames",
730 baseDNList.front());
731 }
732 BMCWEB_LOG_DEBUG << "Updated the base DN";
733 },
734 ldapDbusService, ldapConfigObject, propertyInterface, "Set",
735 ldapConfigInterface, "LDAPBaseDN",
736 std::variant<std::string>(baseDNList.front()));
737 }
738 /**
739 * @brief updates the LDAP user name attribute and updates the
740 json response with the new value.
741 * @param userNameAttribute attribute to be updated.
742 * @param asyncResp pointer to the JSON response
743 * @param ldapServerElementName Type of LDAP
744 server(openLDAP/ActiveDirectory)
745 */
746
747 void handleUserNameAttrPatch(const std::string& userNameAttribute,
748 const std::shared_ptr<AsyncResp>& asyncResp,
749 const std::string& ldapServerElementName,
750 const std::string& ldapConfigObject)
751 {
752 crow::connections::systemBus->async_method_call(
753 [asyncResp, userNameAttribute,
754 ldapServerElementName](const boost::system::error_code ec) {
755 if (ec)
756 {
757 BMCWEB_LOG_DEBUG << "Error Occured in Updating the "
758 "username attribute";
759 messages::internalError(asyncResp->res);
760 return;
761 }
762 auto& serverTypeJson =
763 asyncResp->res.jsonValue[ldapServerElementName];
764 auto& searchSettingsJson =
765 serverTypeJson["LDAPService"]["SearchSettings"];
766 searchSettingsJson["UsernameAttribute"] = userNameAttribute;
767 BMCWEB_LOG_DEBUG << "Updated the user name attr.";
768 },
769 ldapDbusService, ldapConfigObject, propertyInterface, "Set",
770 ldapConfigInterface, "UserNameAttribute",
771 std::variant<std::string>(userNameAttribute));
772 }
773 /**
774 * @brief updates the LDAP group attribute and updates the
775 json response with the new value.
776 * @param groupsAttribute attribute to be updated.
777 * @param asyncResp pointer to the JSON response
778 * @param ldapServerElementName Type of LDAP
779 server(openLDAP/ActiveDirectory)
780 */
781
782 void handleGroupNameAttrPatch(const std::string& groupsAttribute,
783 const std::shared_ptr<AsyncResp>& asyncResp,
784 const std::string& ldapServerElementName,
785 const std::string& ldapConfigObject)
786 {
787 crow::connections::systemBus->async_method_call(
788 [asyncResp, groupsAttribute,
789 ldapServerElementName](const boost::system::error_code ec) {
790 if (ec)
791 {
792 BMCWEB_LOG_DEBUG << "Error Occured in Updating the "
793 "groupname attribute";
794 messages::internalError(asyncResp->res);
795 return;
796 }
797 auto& serverTypeJson =
798 asyncResp->res.jsonValue[ldapServerElementName];
799 auto& searchSettingsJson =
800 serverTypeJson["LDAPService"]["SearchSettings"];
801 searchSettingsJson["GroupsAttribute"] = groupsAttribute;
802 BMCWEB_LOG_DEBUG << "Updated the groupname attr";
803 },
804 ldapDbusService, ldapConfigObject, propertyInterface, "Set",
805 ldapConfigInterface, "GroupNameAttribute",
806 std::variant<std::string>(groupsAttribute));
807 }
808 /**
809 * @brief updates the LDAP service enable and updates the
810 json response with the new value.
811 * @param input JSON data.
812 * @param asyncResp pointer to the JSON response
813 * @param ldapServerElementName Type of LDAP
814 server(openLDAP/ActiveDirectory)
815 */
816
817 void handleServiceEnablePatch(bool serviceEnabled,
818 const std::shared_ptr<AsyncResp>& asyncResp,
819 const std::string& ldapServerElementName,
820 const std::string& ldapConfigObject)
821 {
822 crow::connections::systemBus->async_method_call(
823 [asyncResp, serviceEnabled,
824 ldapServerElementName](const boost::system::error_code ec) {
825 if (ec)
826 {
827 BMCWEB_LOG_DEBUG
828 << "Error Occured in Updating the service enable";
829 messages::internalError(asyncResp->res);
830 return;
831 }
832 asyncResp->res
833 .jsonValue[ldapServerElementName]["ServiceEnabled"] =
834 serviceEnabled;
835 BMCWEB_LOG_DEBUG << "Updated Service enable = "
836 << serviceEnabled;
837 },
838 ldapDbusService, ldapConfigObject, propertyInterface, "Set",
839 ldapEnableInterface, "Enabled", std::variant<bool>(serviceEnabled));
840 }
841
842 /**
843 * @brief Get the required values from the given JSON, validates the
844 * value and create the LDAP config object.
845 * @param input JSON data
846 * @param asyncResp pointer to the JSON response
847 * @param serverType Type of LDAP server(openLDAP/ActiveDirectory)
848 */
849
850 void handleLDAPPatch(nlohmann::json& input,
851 const std::shared_ptr<AsyncResp>& asyncResp,
852 const crow::Request& req,
853 const std::vector<std::string>& params,
854 const std::string& serverType)
855 {
Ratan Guptaeb2bbe52019-04-22 14:27:01 +0530856 std::string dbusObjectPath;
857 if (serverType == "ActiveDirectory")
858 {
859 dbusObjectPath = ADConfigObject;
860 }
861 else if (serverType == "LDAP")
862 {
863 dbusObjectPath = ldapConfigObject;
864 }
865
Ratan Gupta8a07d282019-03-16 08:33:47 +0530866 std::optional<nlohmann::json> authentication;
867 std::optional<nlohmann::json> ldapService;
868 std::optional<std::string> accountProviderType;
869 std::optional<std::vector<std::string>> serviceAddressList;
870 std::optional<bool> serviceEnabled;
871 std::optional<std::vector<std::string>> baseDNList;
872 std::optional<std::string> userNameAttribute;
873 std::optional<std::string> groupsAttribute;
874 std::optional<std::string> userName;
875 std::optional<std::string> password;
Ratan Gupta06785242019-07-26 22:30:16 +0530876 std::optional<std::vector<nlohmann::json>> remoteRoleMapData;
Ratan Gupta8a07d282019-03-16 08:33:47 +0530877
878 if (!json_util::readJson(input, asyncResp->res, "Authentication",
879 authentication, "LDAPService", ldapService,
880 "ServiceAddresses", serviceAddressList,
881 "AccountProviderType", accountProviderType,
Ratan Gupta06785242019-07-26 22:30:16 +0530882 "ServiceEnabled", serviceEnabled,
883 "RemoteRoleMapping", remoteRoleMapData))
Ratan Gupta8a07d282019-03-16 08:33:47 +0530884 {
885 return;
886 }
887
888 if (authentication)
889 {
890 parseLDAPAuthenticationJson(*authentication, asyncResp, userName,
891 password);
892 }
893 if (ldapService)
894 {
895 parseLDAPServiceJson(*ldapService, asyncResp, baseDNList,
896 userNameAttribute, groupsAttribute);
897 }
898 if (accountProviderType)
899 {
900 messages::propertyNotWritable(asyncResp->res,
901 "AccountProviderType");
902 }
903 if (serviceAddressList)
904 {
905 if ((*serviceAddressList).size() == 0)
906 {
907 messages::propertyValueNotInList(asyncResp->res, "[]",
908 "ServiceAddress");
909 return;
910 }
911 }
912 if (baseDNList)
913 {
914 if ((*baseDNList).size() == 0)
915 {
916 messages::propertyValueNotInList(asyncResp->res, "[]",
917 "BaseDistinguishedNames");
918 return;
919 }
920 }
921
922 // nothing to update, then return
923 if (!userName && !password && !serviceAddressList && !baseDNList &&
Ratan Gupta06785242019-07-26 22:30:16 +0530924 !userNameAttribute && !groupsAttribute && !serviceEnabled &&
925 !remoteRoleMapData)
Ratan Gupta8a07d282019-03-16 08:33:47 +0530926 {
927 return;
928 }
929
930 // Get the existing resource first then keep modifying
931 // whenever any property gets updated.
Ratan Guptaab828d72019-04-22 14:18:33 +0530932 getLDAPConfigData(serverType, [this, asyncResp, userName, password,
933 baseDNList, userNameAttribute,
934 groupsAttribute, accountProviderType,
Ratan Guptaeb2bbe52019-04-22 14:27:01 +0530935 serviceAddressList, serviceEnabled,
Ratan Gupta06785242019-07-26 22:30:16 +0530936 dbusObjectPath, remoteRoleMapData](
Ratan Guptaab828d72019-04-22 14:18:33 +0530937 bool success, LDAPConfigData confData,
938 const std::string& serverType) {
939 if (!success)
940 {
941 messages::internalError(asyncResp->res);
942 return;
943 }
944 parseLDAPConfigData(asyncResp->res.jsonValue, confData, serverType);
945 if (confData.serviceEnabled)
946 {
947 // Disable the service first and update the rest of
948 // the properties.
949 handleServiceEnablePatch(false, asyncResp, serverType,
Ratan Guptaeb2bbe52019-04-22 14:27:01 +0530950 dbusObjectPath);
Ratan Guptaab828d72019-04-22 14:18:33 +0530951 }
Ratan Gupta8a07d282019-03-16 08:33:47 +0530952
Ratan Guptaab828d72019-04-22 14:18:33 +0530953 if (serviceAddressList)
954 {
955 handleServiceAddressPatch(*serviceAddressList, asyncResp,
Ratan Guptaeb2bbe52019-04-22 14:27:01 +0530956 serverType, dbusObjectPath);
Ratan Guptaab828d72019-04-22 14:18:33 +0530957 }
958 if (userName)
959 {
960 handleUserNamePatch(*userName, asyncResp, serverType,
Ratan Guptaeb2bbe52019-04-22 14:27:01 +0530961 dbusObjectPath);
Ratan Guptaab828d72019-04-22 14:18:33 +0530962 }
963 if (password)
964 {
965 handlePasswordPatch(*password, asyncResp, serverType,
Ratan Guptaeb2bbe52019-04-22 14:27:01 +0530966 dbusObjectPath);
Ratan Guptaab828d72019-04-22 14:18:33 +0530967 }
Ratan Gupta8a07d282019-03-16 08:33:47 +0530968
Ratan Guptaab828d72019-04-22 14:18:33 +0530969 if (baseDNList)
970 {
971 handleBaseDNPatch(*baseDNList, asyncResp, serverType,
Ratan Guptaeb2bbe52019-04-22 14:27:01 +0530972 dbusObjectPath);
Ratan Guptaab828d72019-04-22 14:18:33 +0530973 }
974 if (userNameAttribute)
975 {
976 handleUserNameAttrPatch(*userNameAttribute, asyncResp,
Ratan Guptaeb2bbe52019-04-22 14:27:01 +0530977 serverType, dbusObjectPath);
Ratan Guptaab828d72019-04-22 14:18:33 +0530978 }
979 if (groupsAttribute)
980 {
981 handleGroupNameAttrPatch(*groupsAttribute, asyncResp,
Ratan Guptaeb2bbe52019-04-22 14:27:01 +0530982 serverType, dbusObjectPath);
Ratan Guptaab828d72019-04-22 14:18:33 +0530983 }
984 if (serviceEnabled)
985 {
986 // if user has given the value as true then enable
987 // the service. if user has given false then no-op
988 // as service is already stopped.
989 if (*serviceEnabled)
Ratan Gupta8a07d282019-03-16 08:33:47 +0530990 {
Ratan Guptaab828d72019-04-22 14:18:33 +0530991 handleServiceEnablePatch(*serviceEnabled, asyncResp,
Ratan Guptaeb2bbe52019-04-22 14:27:01 +0530992 serverType, dbusObjectPath);
Ratan Gupta8a07d282019-03-16 08:33:47 +0530993 }
Ratan Guptaab828d72019-04-22 14:18:33 +0530994 }
995 else
996 {
997 // if user has not given the service enabled value
998 // then revert it to the same state as it was
999 // before.
1000 handleServiceEnablePatch(confData.serviceEnabled, asyncResp,
Ratan Guptaeb2bbe52019-04-22 14:27:01 +05301001 serverType, dbusObjectPath);
Ratan Guptaab828d72019-04-22 14:18:33 +05301002 }
Ratan Gupta06785242019-07-26 22:30:16 +05301003
1004 if (remoteRoleMapData)
1005 {
1006 std::vector<nlohmann::json> remoteRoleMap =
1007 std::move(*remoteRoleMapData);
1008
1009 handleRoleMapPatch(asyncResp, confData.groupRoleList,
1010 serverType, remoteRoleMap);
1011 }
Ratan Guptaab828d72019-04-22 14:18:33 +05301012 });
Ratan Gupta8a07d282019-03-16 08:33:47 +05301013 }
Ed Tanousd4b54432019-07-17 22:51:55 +00001014
Ed Tanous1abe55e2018-09-05 08:30:59 -07001015 void doGet(crow::Response& res, const crow::Request& req,
1016 const std::vector<std::string>& params) override
1017 {
AppaRao Puli3d958bb2018-12-25 12:45:54 +05301018 auto asyncResp = std::make_shared<AsyncResp>(res);
1019 res.jsonValue = {
1020 {"@odata.context", "/redfish/v1/"
1021 "$metadata#AccountService.AccountService"},
1022 {"@odata.id", "/redfish/v1/AccountService"},
1023 {"@odata.type", "#AccountService."
Marri Devender Rao37cce912019-02-20 01:05:22 -06001024 "v1_4_0.AccountService"},
AppaRao Puli3d958bb2018-12-25 12:45:54 +05301025 {"Id", "AccountService"},
1026 {"Name", "Account Service"},
1027 {"Description", "Account Service"},
1028 {"ServiceEnabled", true},
AppaRao Puli343ff2e2019-03-24 00:42:13 +05301029 {"MaxPasswordLength", 20},
AppaRao Puli3d958bb2018-12-25 12:45:54 +05301030 {"Accounts",
1031 {{"@odata.id", "/redfish/v1/AccountService/Accounts"}}},
Marri Devender Rao37cce912019-02-20 01:05:22 -06001032 {"Roles", {{"@odata.id", "/redfish/v1/AccountService/Roles"}}},
1033 {"LDAP",
1034 {{"Certificates",
1035 {{"@odata.id",
1036 "/redfish/v1/AccountService/LDAP/Certificates"}}}}}};
AppaRao Puli3d958bb2018-12-25 12:45:54 +05301037 crow::connections::systemBus->async_method_call(
1038 [asyncResp](
1039 const boost::system::error_code ec,
1040 const std::vector<std::pair<
Ed Tanousabf2add2019-01-22 16:40:12 -08001041 std::string, std::variant<uint32_t, uint16_t, uint8_t>>>&
AppaRao Puli3d958bb2018-12-25 12:45:54 +05301042 propertiesList) {
1043 if (ec)
1044 {
1045 messages::internalError(asyncResp->res);
1046 return;
1047 }
1048 BMCWEB_LOG_DEBUG << "Got " << propertiesList.size()
1049 << "properties for AccountService";
1050 for (const std::pair<std::string,
Ed Tanousabf2add2019-01-22 16:40:12 -08001051 std::variant<uint32_t, uint16_t, uint8_t>>&
AppaRao Puli3d958bb2018-12-25 12:45:54 +05301052 property : propertiesList)
1053 {
1054 if (property.first == "MinPasswordLength")
1055 {
1056 const uint8_t* value =
Ed Tanousabf2add2019-01-22 16:40:12 -08001057 std::get_if<uint8_t>(&property.second);
AppaRao Puli3d958bb2018-12-25 12:45:54 +05301058 if (value != nullptr)
1059 {
1060 asyncResp->res.jsonValue["MinPasswordLength"] =
1061 *value;
1062 }
1063 }
1064 if (property.first == "AccountUnlockTimeout")
1065 {
1066 const uint32_t* value =
Ed Tanousabf2add2019-01-22 16:40:12 -08001067 std::get_if<uint32_t>(&property.second);
AppaRao Puli3d958bb2018-12-25 12:45:54 +05301068 if (value != nullptr)
1069 {
1070 asyncResp->res.jsonValue["AccountLockoutDuration"] =
1071 *value;
1072 }
1073 }
1074 if (property.first == "MaxLoginAttemptBeforeLockout")
1075 {
1076 const uint16_t* value =
Ed Tanousabf2add2019-01-22 16:40:12 -08001077 std::get_if<uint16_t>(&property.second);
AppaRao Puli3d958bb2018-12-25 12:45:54 +05301078 if (value != nullptr)
1079 {
1080 asyncResp->res
1081 .jsonValue["AccountLockoutThreshold"] = *value;
1082 }
1083 }
1084 }
1085 },
1086 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
1087 "org.freedesktop.DBus.Properties", "GetAll",
1088 "xyz.openbmc_project.User.AccountPolicy");
Ratan Gupta6973a582018-12-13 18:25:44 +05301089
Ratan Guptaab828d72019-04-22 14:18:33 +05301090 auto callback = [asyncResp](bool success, LDAPConfigData& confData,
1091 const std::string& ldapType) {
1092 parseLDAPConfigData(asyncResp->res.jsonValue, confData, ldapType);
1093 };
1094
1095 getLDAPConfigData("LDAP", callback);
1096 getLDAPConfigData("ActiveDirectory", callback);
AppaRao Puli3d958bb2018-12-25 12:45:54 +05301097 }
Ratan Gupta6973a582018-12-13 18:25:44 +05301098
AppaRao Puli3d958bb2018-12-25 12:45:54 +05301099 void doPatch(crow::Response& res, const crow::Request& req,
1100 const std::vector<std::string>& params) override
1101 {
1102 auto asyncResp = std::make_shared<AsyncResp>(res);
1103
1104 std::optional<uint32_t> unlockTimeout;
1105 std::optional<uint16_t> lockoutThreshold;
Ratan Gupta19fb6e72019-03-04 13:30:50 +05301106 std::optional<uint16_t> minPasswordLength;
1107 std::optional<uint16_t> maxPasswordLength;
Ratan Gupta8a07d282019-03-16 08:33:47 +05301108 std::optional<nlohmann::json> ldapObject;
Ratan Guptaeb2bbe52019-04-22 14:27:01 +05301109 std::optional<nlohmann::json> activeDirectoryObject;
Ratan Gupta19fb6e72019-03-04 13:30:50 +05301110
AppaRao Puli3d958bb2018-12-25 12:45:54 +05301111 if (!json_util::readJson(req, res, "AccountLockoutDuration",
1112 unlockTimeout, "AccountLockoutThreshold",
Ratan Gupta19fb6e72019-03-04 13:30:50 +05301113 lockoutThreshold, "MaxPasswordLength",
1114 maxPasswordLength, "MinPasswordLength",
Ratan Guptaeb2bbe52019-04-22 14:27:01 +05301115 minPasswordLength, "LDAP", ldapObject,
1116 "ActiveDirectory", activeDirectoryObject))
AppaRao Puli3d958bb2018-12-25 12:45:54 +05301117 {
1118 return;
1119 }
Ratan Gupta19fb6e72019-03-04 13:30:50 +05301120
1121 if (minPasswordLength)
1122 {
1123 messages::propertyNotWritable(asyncResp->res, "MinPasswordLength");
1124 }
1125
1126 if (maxPasswordLength)
1127 {
1128 messages::propertyNotWritable(asyncResp->res, "MaxPasswordLength");
1129 }
1130
Ratan Gupta8a07d282019-03-16 08:33:47 +05301131 if (ldapObject)
1132 {
1133 handleLDAPPatch(*ldapObject, asyncResp, req, params, "LDAP");
1134 }
1135
Ratan Guptaeb2bbe52019-04-22 14:27:01 +05301136 if (activeDirectoryObject)
1137 {
1138 handleLDAPPatch(*activeDirectoryObject, asyncResp, req, params,
1139 "ActiveDirectory");
1140 }
1141
AppaRao Puli3d958bb2018-12-25 12:45:54 +05301142 if (unlockTimeout)
1143 {
1144 crow::connections::systemBus->async_method_call(
1145 [asyncResp](const boost::system::error_code ec) {
1146 if (ec)
1147 {
1148 messages::internalError(asyncResp->res);
1149 return;
1150 }
Ratan Guptaadd61332019-02-13 20:49:16 +05301151 messages::success(asyncResp->res);
AppaRao Puli3d958bb2018-12-25 12:45:54 +05301152 },
1153 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
1154 "org.freedesktop.DBus.Properties", "Set",
1155 "xyz.openbmc_project.User.AccountPolicy",
Ed Tanousabf2add2019-01-22 16:40:12 -08001156 "AccountUnlockTimeout", std::variant<uint32_t>(*unlockTimeout));
AppaRao Puli3d958bb2018-12-25 12:45:54 +05301157 }
1158 if (lockoutThreshold)
1159 {
1160 crow::connections::systemBus->async_method_call(
1161 [asyncResp](const boost::system::error_code ec) {
1162 if (ec)
1163 {
1164 messages::internalError(asyncResp->res);
1165 return;
1166 }
Ratan Guptaadd61332019-02-13 20:49:16 +05301167 messages::success(asyncResp->res);
AppaRao Puli3d958bb2018-12-25 12:45:54 +05301168 },
1169 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
1170 "org.freedesktop.DBus.Properties", "Set",
1171 "xyz.openbmc_project.User.AccountPolicy",
1172 "MaxLoginAttemptBeforeLockout",
Ed Tanousabf2add2019-01-22 16:40:12 -08001173 std::variant<uint16_t>(*lockoutThreshold));
AppaRao Puli3d958bb2018-12-25 12:45:54 +05301174 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001175 }
Lewanczyk, Dawid88d16c92018-02-02 14:51:09 +01001176};
Tanousf00032d2018-11-05 01:18:10 -03001177
Ed Tanousb9b2e0b2018-09-13 13:47:50 -07001178class AccountsCollection : public Node
1179{
1180 public:
1181 AccountsCollection(CrowApp& app) :
1182 Node(app, "/redfish/v1/AccountService/Accounts/")
1183 {
Ed Tanousb9b2e0b2018-09-13 13:47:50 -07001184 entityPrivileges = {
1185 {boost::beast::http::verb::get,
1186 {{"ConfigureUsers"}, {"ConfigureManager"}}},
1187 {boost::beast::http::verb::head, {{"Login"}}},
1188 {boost::beast::http::verb::patch, {{"ConfigureUsers"}}},
1189 {boost::beast::http::verb::put, {{"ConfigureUsers"}}},
1190 {boost::beast::http::verb::delete_, {{"ConfigureUsers"}}},
1191 {boost::beast::http::verb::post, {{"ConfigureUsers"}}}};
1192 }
1193
1194 private:
1195 void doGet(crow::Response& res, const crow::Request& req,
1196 const std::vector<std::string>& params) override
1197 {
Ed Tanousb9b2e0b2018-09-13 13:47:50 -07001198 auto asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous0f74e642018-11-12 15:17:05 -08001199 res.jsonValue = {{"@odata.context",
1200 "/redfish/v1/"
1201 "$metadata#ManagerAccountCollection."
1202 "ManagerAccountCollection"},
1203 {"@odata.id", "/redfish/v1/AccountService/Accounts"},
1204 {"@odata.type", "#ManagerAccountCollection."
1205 "ManagerAccountCollection"},
1206 {"Name", "Accounts Collection"},
1207 {"Description", "BMC User Accounts"}};
1208
Ed Tanousb9b2e0b2018-09-13 13:47:50 -07001209 crow::connections::systemBus->async_method_call(
1210 [asyncResp](const boost::system::error_code ec,
1211 const ManagedObjectType& users) {
1212 if (ec)
1213 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001214 messages::internalError(asyncResp->res);
Ed Tanousb9b2e0b2018-09-13 13:47:50 -07001215 return;
1216 }
1217
1218 nlohmann::json& memberArray =
1219 asyncResp->res.jsonValue["Members"];
1220 memberArray = nlohmann::json::array();
1221
1222 asyncResp->res.jsonValue["Members@odata.count"] = users.size();
1223 for (auto& user : users)
1224 {
1225 const std::string& path =
1226 static_cast<const std::string&>(user.first);
1227 std::size_t lastIndex = path.rfind("/");
1228 if (lastIndex == std::string::npos)
1229 {
1230 lastIndex = 0;
1231 }
1232 else
1233 {
1234 lastIndex += 1;
1235 }
1236 memberArray.push_back(
1237 {{"@odata.id", "/redfish/v1/AccountService/Accounts/" +
1238 path.substr(lastIndex)}});
1239 }
1240 },
1241 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
1242 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
1243 }
Ed Tanous04ae99e2018-09-20 15:54:36 -07001244 void doPost(crow::Response& res, const crow::Request& req,
1245 const std::vector<std::string>& params) override
1246 {
1247 auto asyncResp = std::make_shared<AsyncResp>(res);
1248
Ed Tanous9712f8a2018-09-21 13:38:49 -07001249 std::string username;
1250 std::string password;
Ed Tanousa24526d2018-12-10 15:17:59 -08001251 std::optional<std::string> roleId("User");
1252 std::optional<bool> enabled = true;
Ed Tanous9712f8a2018-09-21 13:38:49 -07001253 if (!json_util::readJson(req, res, "UserName", username, "Password",
1254 password, "RoleId", roleId, "Enabled",
1255 enabled))
Ed Tanous04ae99e2018-09-20 15:54:36 -07001256 {
1257 return;
1258 }
1259
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -06001260 std::string priv = getPrivilegeFromRoleId(*roleId);
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301261 if (priv.empty())
Ed Tanous04ae99e2018-09-20 15:54:36 -07001262 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001263 messages::propertyValueNotInList(asyncResp->res, *roleId, "RoleId");
Ed Tanous04ae99e2018-09-20 15:54:36 -07001264 return;
1265 }
Ed Tanous9712f8a2018-09-21 13:38:49 -07001266 roleId = priv;
Ed Tanous04ae99e2018-09-20 15:54:36 -07001267
Ayushi Smriti599c71d2019-08-23 17:43:18 +00001268 // Reading AllGroups property
Ed Tanous04ae99e2018-09-20 15:54:36 -07001269 crow::connections::systemBus->async_method_call(
Ayushi Smriti599c71d2019-08-23 17:43:18 +00001270 [asyncResp, username, password{std::move(password)}, roleId,
1271 enabled](const boost::system::error_code ec,
1272 const std::variant<std::vector<std::string>>& allGroups) {
Ed Tanous04ae99e2018-09-20 15:54:36 -07001273 if (ec)
1274 {
Ayushi Smriti599c71d2019-08-23 17:43:18 +00001275 BMCWEB_LOG_DEBUG << "ERROR with async_method_call";
1276 messages::internalError(asyncResp->res);
Ed Tanous04ae99e2018-09-20 15:54:36 -07001277 return;
1278 }
1279
Ayushi Smriti599c71d2019-08-23 17:43:18 +00001280 const std::vector<std::string>* allGroupsList =
1281 std::get_if<std::vector<std::string>>(&allGroups);
1282
1283 if (allGroupsList == nullptr || allGroupsList->empty())
Ed Tanous04ae99e2018-09-20 15:54:36 -07001284 {
Ayushi Smriti599c71d2019-08-23 17:43:18 +00001285 messages::internalError(asyncResp->res);
Ed Tanous04ae99e2018-09-20 15:54:36 -07001286 return;
1287 }
1288
Ayushi Smriti599c71d2019-08-23 17:43:18 +00001289 crow::connections::systemBus->async_method_call(
1290 [asyncResp, username, password{std::move(password)}](
1291 const boost::system::error_code ec) {
1292 if (ec)
1293 {
1294 messages::resourceAlreadyExists(
1295 asyncResp->res,
1296 "#ManagerAccount.v1_0_3.ManagerAccount",
1297 "UserName", username);
1298 return;
1299 }
1300
1301 if (!pamUpdatePassword(username, password))
1302 {
1303 // At this point we have a user that's been created,
1304 // but the password set failed.Something is wrong,
1305 // so delete the user that we've already created
1306 crow::connections::systemBus->async_method_call(
1307 [asyncResp](
1308 const boost::system::error_code ec) {
1309 if (ec)
1310 {
1311 messages::internalError(asyncResp->res);
1312 return;
1313 }
1314
1315 messages::invalidObject(asyncResp->res,
1316 "Password");
1317 },
1318 "xyz.openbmc_project.User.Manager",
1319 "/xyz/openbmc_project/user/" + username,
1320 "xyz.openbmc_project.Object.Delete", "Delete");
1321
1322 BMCWEB_LOG_ERROR << "pamUpdatePassword Failed";
1323 return;
1324 }
1325
1326 messages::created(asyncResp->res);
1327 asyncResp->res.addHeader(
1328 "Location",
1329 "/redfish/v1/AccountService/Accounts/" + username);
1330 },
1331 "xyz.openbmc_project.User.Manager",
1332 "/xyz/openbmc_project/user",
1333 "xyz.openbmc_project.User.Manager", "CreateUser", username,
1334 *allGroupsList, *roleId, *enabled);
Ed Tanous04ae99e2018-09-20 15:54:36 -07001335 },
1336 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
Ayushi Smriti599c71d2019-08-23 17:43:18 +00001337 "org.freedesktop.DBus.Properties", "Get",
1338 "xyz.openbmc_project.User.Manager", "AllGroups");
Ed Tanous04ae99e2018-09-20 15:54:36 -07001339 }
Ed Tanousb9b2e0b2018-09-13 13:47:50 -07001340};
1341
1342class ManagerAccount : public Node
1343{
1344 public:
1345 ManagerAccount(CrowApp& app) :
1346 Node(app, "/redfish/v1/AccountService/Accounts/<str>/", std::string())
1347 {
Ed Tanousb9b2e0b2018-09-13 13:47:50 -07001348 entityPrivileges = {
1349 {boost::beast::http::verb::get,
1350 {{"ConfigureUsers"}, {"ConfigureManager"}, {"ConfigureSelf"}}},
1351 {boost::beast::http::verb::head, {{"Login"}}},
1352 {boost::beast::http::verb::patch, {{"ConfigureUsers"}}},
1353 {boost::beast::http::verb::put, {{"ConfigureUsers"}}},
1354 {boost::beast::http::verb::delete_, {{"ConfigureUsers"}}},
1355 {boost::beast::http::verb::post, {{"ConfigureUsers"}}}};
1356 }
1357
1358 private:
1359 void doGet(crow::Response& res, const crow::Request& req,
1360 const std::vector<std::string>& params) override
1361 {
Ed Tanous0f74e642018-11-12 15:17:05 -08001362
Ed Tanousb9b2e0b2018-09-13 13:47:50 -07001363 auto asyncResp = std::make_shared<AsyncResp>(res);
1364
1365 if (params.size() != 1)
1366 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001367 messages::internalError(asyncResp->res);
Ed Tanousb9b2e0b2018-09-13 13:47:50 -07001368 return;
1369 }
1370
1371 crow::connections::systemBus->async_method_call(
1372 [asyncResp, accountName{std::string(params[0])}](
1373 const boost::system::error_code ec,
1374 const ManagedObjectType& users) {
1375 if (ec)
1376 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001377 messages::internalError(asyncResp->res);
Ed Tanousb9b2e0b2018-09-13 13:47:50 -07001378 return;
1379 }
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301380 auto userIt = users.begin();
Ed Tanousb9b2e0b2018-09-13 13:47:50 -07001381
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301382 for (; userIt != users.end(); userIt++)
Ed Tanousb9b2e0b2018-09-13 13:47:50 -07001383 {
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301384 if (boost::ends_with(userIt->first.str, "/" + accountName))
Ed Tanousb9b2e0b2018-09-13 13:47:50 -07001385 {
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301386 break;
Ed Tanousb9b2e0b2018-09-13 13:47:50 -07001387 }
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301388 }
1389 if (userIt == users.end())
1390 {
1391 messages::resourceNotFound(asyncResp->res, "ManagerAccount",
1392 accountName);
1393 return;
1394 }
Ayushi Smriti4e68c452019-09-04 14:37:55 +05301395
1396 asyncResp->res.jsonValue = {
1397 {"@odata.context",
1398 "/redfish/v1/$metadata#ManagerAccount.ManagerAccount"},
1399 {"@odata.type", "#ManagerAccount.v1_0_3.ManagerAccount"},
1400 {"Name", "User Account"},
1401 {"Description", "User Account"},
1402 {"Password", nullptr}};
1403
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301404 for (const auto& interface : userIt->second)
1405 {
1406 if (interface.first ==
1407 "xyz.openbmc_project.User.Attributes")
Ed Tanousb9b2e0b2018-09-13 13:47:50 -07001408 {
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301409 for (const auto& property : interface.second)
Ed Tanous65b0dc32018-09-19 16:04:03 -07001410 {
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301411 if (property.first == "UserEnabled")
Ed Tanous65b0dc32018-09-19 16:04:03 -07001412 {
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301413 const bool* userEnabled =
Ed Tanousabf2add2019-01-22 16:40:12 -08001414 std::get_if<bool>(&property.second);
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301415 if (userEnabled == nullptr)
Ed Tanous65b0dc32018-09-19 16:04:03 -07001416 {
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301417 BMCWEB_LOG_ERROR
1418 << "UserEnabled wasn't a bool";
1419 messages::internalError(asyncResp->res);
1420 return;
Ed Tanous65b0dc32018-09-19 16:04:03 -07001421 }
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301422 asyncResp->res.jsonValue["Enabled"] =
1423 *userEnabled;
1424 }
1425 else if (property.first ==
1426 "UserLockedForFailedAttempt")
1427 {
1428 const bool* userLocked =
Ed Tanousabf2add2019-01-22 16:40:12 -08001429 std::get_if<bool>(&property.second);
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301430 if (userLocked == nullptr)
1431 {
1432 BMCWEB_LOG_ERROR << "UserLockedForF"
1433 "ailedAttempt "
1434 "wasn't a bool";
1435 messages::internalError(asyncResp->res);
1436 return;
1437 }
1438 asyncResp->res.jsonValue["Locked"] =
1439 *userLocked;
Ratan Gupta24c85422019-01-30 19:41:24 +05301440 asyncResp->res.jsonValue
1441 ["Locked@Redfish.AllowableValues"] = {
Gunnar Mills4d64ce32019-03-29 16:34:56 -05001442 "false"};
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301443 }
1444 else if (property.first == "UserPrivilege")
1445 {
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -06001446 const std::string* userPrivPtr =
Ed Tanousabf2add2019-01-22 16:40:12 -08001447 std::get_if<std::string>(&property.second);
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -06001448 if (userPrivPtr == nullptr)
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301449 {
1450 BMCWEB_LOG_ERROR
1451 << "UserPrivilege wasn't a "
1452 "string";
1453 messages::internalError(asyncResp->res);
1454 return;
1455 }
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -06001456 std::string role =
1457 getRoleIdFromPrivilege(*userPrivPtr);
1458 if (role.empty())
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301459 {
1460 BMCWEB_LOG_ERROR << "Invalid user role";
1461 messages::internalError(asyncResp->res);
1462 return;
1463 }
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -06001464 asyncResp->res.jsonValue["RoleId"] = role;
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301465
1466 asyncResp->res.jsonValue["Links"]["Role"] = {
1467 {"@odata.id", "/redfish/v1/AccountService/"
1468 "Roles/" +
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -06001469 role}};
Ed Tanous65b0dc32018-09-19 16:04:03 -07001470 }
1471 }
Ed Tanousb9b2e0b2018-09-13 13:47:50 -07001472 }
1473 }
1474
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301475 asyncResp->res.jsonValue["@odata.id"] =
1476 "/redfish/v1/AccountService/Accounts/" + accountName;
1477 asyncResp->res.jsonValue["Id"] = accountName;
1478 asyncResp->res.jsonValue["UserName"] = accountName;
Ed Tanousb9b2e0b2018-09-13 13:47:50 -07001479 },
1480 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
1481 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
1482 }
Ed Tanousa8408792018-09-05 16:08:38 -07001483
1484 void doPatch(crow::Response& res, const crow::Request& req,
1485 const std::vector<std::string>& params) override
1486 {
1487 auto asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanousa8408792018-09-05 16:08:38 -07001488 if (params.size() != 1)
1489 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001490 messages::internalError(asyncResp->res);
Ed Tanousa8408792018-09-05 16:08:38 -07001491 return;
1492 }
1493
Ed Tanousa24526d2018-12-10 15:17:59 -08001494 std::optional<std::string> newUserName;
1495 std::optional<std::string> password;
1496 std::optional<bool> enabled;
1497 std::optional<std::string> roleId;
Ratan Gupta24c85422019-01-30 19:41:24 +05301498 std::optional<bool> locked;
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301499 if (!json_util::readJson(req, res, "UserName", newUserName, "Password",
Ratan Gupta24c85422019-01-30 19:41:24 +05301500 password, "RoleId", roleId, "Enabled", enabled,
1501 "Locked", locked))
Ed Tanousa8408792018-09-05 16:08:38 -07001502 {
1503 return;
1504 }
1505
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301506 const std::string& username = params[0];
Ed Tanousa8408792018-09-05 16:08:38 -07001507
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301508 if (!newUserName)
1509 {
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -06001510 // If the username isn't being updated, we can update the
1511 // properties directly
Ratan Gupta24c85422019-01-30 19:41:24 +05301512 updateUserProperties(asyncResp, username, password, enabled, roleId,
1513 locked);
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301514 return;
1515 }
1516 else
1517 {
1518 crow::connections::systemBus->async_method_call(
1519 [this, asyncResp, username, password(std::move(password)),
1520 roleId(std::move(roleId)), enabled(std::move(enabled)),
Ed Tanous271584a2019-07-09 16:24:22 -07001521 newUser{*newUserName}, locked(std::move(locked))](
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301522 const boost::system::error_code ec) {
1523 if (ec)
Ed Tanousa8408792018-09-05 16:08:38 -07001524 {
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301525 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
1526 messages::resourceNotFound(
1527 asyncResp->res,
1528 "#ManagerAccount.v1_0_3.ManagerAccount", username);
1529 return;
1530 }
1531
1532 updateUserProperties(asyncResp, newUser, password, enabled,
Ratan Gupta24c85422019-01-30 19:41:24 +05301533 roleId, locked);
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301534 },
1535 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
1536 "xyz.openbmc_project.User.Manager", "RenameUser", username,
1537 *newUserName);
1538 }
1539 }
1540
1541 void updateUserProperties(std::shared_ptr<AsyncResp> asyncResp,
1542 const std::string& username,
Ed Tanousa24526d2018-12-10 15:17:59 -08001543 std::optional<std::string> password,
1544 std::optional<bool> enabled,
Ratan Gupta24c85422019-01-30 19:41:24 +05301545 std::optional<std::string> roleId,
1546 std::optional<bool> locked)
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301547 {
1548 if (password)
1549 {
1550 if (!pamUpdatePassword(username, *password))
1551 {
1552 BMCWEB_LOG_ERROR << "pamUpdatePassword Failed";
1553 messages::internalError(asyncResp->res);
1554 return;
1555 }
1556 }
1557
Ratan Gupta24c85422019-01-30 19:41:24 +05301558 std::string dbusObjectPath = "/xyz/openbmc_project/user/" + username;
1559 dbus::utility::escapePathForDbus(dbusObjectPath);
1560
Ratan Gupta22c33712019-05-03 21:50:28 +05301561 dbus::utility::checkDbusPathExists(
Ratan Gupta24c85422019-01-30 19:41:24 +05301562 dbusObjectPath,
1563 [dbusObjectPath(std::move(dbusObjectPath)), username,
1564 password(std::move(password)), roleId(std::move(roleId)),
1565 enabled(std::move(enabled)), locked(std::move(locked)),
1566 asyncResp{std::move(asyncResp)}](int rc) {
1567 if (!rc)
1568 {
1569 messages::invalidObject(asyncResp->res, username.c_str());
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301570 return;
Ratan Gupta24c85422019-01-30 19:41:24 +05301571 }
1572 if (enabled)
1573 {
1574 crow::connections::systemBus->async_method_call(
1575 [asyncResp](const boost::system::error_code ec) {
1576 if (ec)
1577 {
1578 BMCWEB_LOG_ERROR << "D-Bus responses error: "
1579 << ec;
1580 messages::internalError(asyncResp->res);
1581 return;
1582 }
1583 messages::success(asyncResp->res);
1584 return;
1585 },
1586 "xyz.openbmc_project.User.Manager",
1587 dbusObjectPath.c_str(),
1588 "org.freedesktop.DBus.Properties", "Set",
1589 "xyz.openbmc_project.User.Attributes", "UserEnabled",
1590 std::variant<bool>{*enabled});
1591 }
Ed Tanous9712f8a2018-09-21 13:38:49 -07001592
Ratan Gupta24c85422019-01-30 19:41:24 +05301593 if (roleId)
1594 {
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -06001595 std::string priv = getPrivilegeFromRoleId(*roleId);
Ratan Gupta24c85422019-01-30 19:41:24 +05301596 if (priv.empty())
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301597 {
Ratan Gupta24c85422019-01-30 19:41:24 +05301598 messages::propertyValueNotInList(asyncResp->res,
1599 *roleId, "RoleId");
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301600 return;
1601 }
Ratan Gupta24c85422019-01-30 19:41:24 +05301602
1603 crow::connections::systemBus->async_method_call(
1604 [asyncResp](const boost::system::error_code ec) {
1605 if (ec)
1606 {
1607 BMCWEB_LOG_ERROR << "D-Bus responses error: "
1608 << ec;
1609 messages::internalError(asyncResp->res);
1610 return;
1611 }
1612 messages::success(asyncResp->res);
1613 },
1614 "xyz.openbmc_project.User.Manager",
1615 dbusObjectPath.c_str(),
1616 "org.freedesktop.DBus.Properties", "Set",
1617 "xyz.openbmc_project.User.Attributes", "UserPrivilege",
1618 std::variant<std::string>{priv});
1619 }
1620
1621 if (locked)
1622 {
1623 // admin can unlock the account which is locked by
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -06001624 // successive authentication failures but admin should
1625 // not be allowed to lock an account.
Ratan Gupta24c85422019-01-30 19:41:24 +05301626 if (*locked)
1627 {
1628 messages::propertyValueNotInList(asyncResp->res, "true",
1629 "Locked");
1630 return;
1631 }
1632
1633 crow::connections::systemBus->async_method_call(
1634 [asyncResp](const boost::system::error_code ec) {
1635 if (ec)
1636 {
1637 BMCWEB_LOG_ERROR << "D-Bus responses error: "
1638 << ec;
1639 messages::internalError(asyncResp->res);
1640 return;
1641 }
1642 messages::success(asyncResp->res);
1643 return;
1644 },
1645 "xyz.openbmc_project.User.Manager",
1646 dbusObjectPath.c_str(),
1647 "org.freedesktop.DBus.Properties", "Set",
1648 "xyz.openbmc_project.User.Attributes",
1649 "UserLockedForFailedAttempt",
1650 sdbusplus::message::variant<bool>{*locked});
1651 }
1652 });
Ed Tanousa8408792018-09-05 16:08:38 -07001653 }
Ed Tanous06e086d2018-09-19 17:19:52 -07001654
1655 void doDelete(crow::Response& res, const crow::Request& req,
1656 const std::vector<std::string>& params) override
1657 {
1658 auto asyncResp = std::make_shared<AsyncResp>(res);
1659
1660 if (params.size() != 1)
1661 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001662 messages::internalError(asyncResp->res);
Ed Tanous06e086d2018-09-19 17:19:52 -07001663 return;
1664 }
1665
1666 const std::string userPath = "/xyz/openbmc_project/user/" + params[0];
1667
1668 crow::connections::systemBus->async_method_call(
1669 [asyncResp, username{std::move(params[0])}](
1670 const boost::system::error_code ec) {
1671 if (ec)
1672 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001673 messages::resourceNotFound(
1674 asyncResp->res, "#ManagerAccount.v1_0_3.ManagerAccount",
1675 username);
Ed Tanous06e086d2018-09-19 17:19:52 -07001676 return;
1677 }
1678
Jason M. Billsf12894f2018-10-09 12:45:45 -07001679 messages::accountRemoved(asyncResp->res);
Ed Tanous06e086d2018-09-19 17:19:52 -07001680 },
1681 "xyz.openbmc_project.User.Manager", userPath,
1682 "xyz.openbmc_project.Object.Delete", "Delete");
1683 }
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301684};
Lewanczyk, Dawid88d16c92018-02-02 14:51:09 +01001685
Ed Tanous1abe55e2018-09-05 08:30:59 -07001686} // namespace redfish