blob: d4e1b38ea76c5e7091635811d436d9545001a76b [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";
Nagaraju Goruganti2a21b9d2019-01-31 05:24:27 -060040constexpr 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/**
Nagaraju Goruganti2a21b9d2019-01-31 05:24:27 -0600154 * @brief deletes given RoleMapping Object.
155 */
156static void deleteRoleMappingObject(const std::shared_ptr<AsyncResp>& asyncResp,
157 const std::string& objPath,
158 const std::string& serverType,
159 unsigned int index)
160{
161
162 BMCWEB_LOG_DEBUG << "deleteRoleMappingObject objPath =" << objPath;
163
164 crow::connections::systemBus->async_method_call(
165 [asyncResp, serverType, index](const boost::system::error_code ec) {
166 if (ec)
167 {
168 BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
169 messages::internalError(asyncResp->res);
170 return;
171 }
172 asyncResp->res.jsonValue[serverType]["RemoteRoleMapping"][index] =
173 nullptr;
174 },
175 ldapDbusService, objPath, "xyz.openbmc_project.Object.Delete",
176 "Delete");
177}
178
179/**
180 * @brief sets RoleMapping Object's property with given value.
181 */
182static void setRoleMappingProperty(
183 const std::shared_ptr<AsyncResp>& asyncResp, const std::string& objPath,
184 const std::string& redfishProperty, const std::string& dbusProperty,
185 const std::string& value, const std::string& serverType, unsigned int index)
186{
187 BMCWEB_LOG_DEBUG << "setRoleMappingProperty objPath: " << objPath
188 << "value: " << value;
189
190 // need to get the dbus privilege from the given refish role
191 std::string dbusVal = value;
192 if (redfishProperty == "LocalRole")
193 {
194 dbusVal = getPrivilegeFromRoleId(value);
195 }
196
197 crow::connections::systemBus->async_method_call(
198 [asyncResp, serverType, index, redfishProperty,
199 value](const boost::system::error_code ec) {
200 if (ec)
201 {
202 BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
203 messages::internalError(asyncResp->res);
204 return;
205 }
206 asyncResp->res.jsonValue[serverType]["RemoteRoleMapping"][index]
207 [redfishProperty] = value;
208 },
209 ldapDbusService, objPath, "org.freedesktop.DBus.Properties", "Set",
210 "xyz.openbmc_project.User.PrivilegeMapperEntry",
211 std::move(dbusProperty), std::variant<std::string>(std::move(dbusVal)));
212}
213
214/**
215 * @brief validates given JSON input and then calls appropriate method to
216 * create, to delete or to set Rolemapping object based on the given input.
217 *
218 */
219static void handleRoleMapPatch(
220 const std::shared_ptr<AsyncResp>& asyncResp,
221 const std::vector<std::pair<std::string, LDAPRoleMapData>>& roleMapObjData,
222 const std::string& serverType, const nlohmann::json& input)
223{
224 if (!input.is_array())
225 {
226 messages::propertyValueTypeError(asyncResp->res, input.dump(),
227 "RemoteRoleMapping");
228 return;
229 }
230
231 size_t index = 0;
232 for (const nlohmann::json& thisJson : input)
233 {
234 // Check that entry is not of some unexpected type
235 if (!thisJson.is_object() && !thisJson.is_null())
236 {
237 messages::propertyValueTypeError(asyncResp->res, thisJson.dump(),
238 "RemoteGroup or LocalRole");
239 index++;
240 continue;
241 }
242 BMCWEB_LOG_DEBUG << "JSON=" << thisJson << "\n";
243 // delete the existing object
244 if (thisJson.is_null())
245 {
246 if (input.size() <= roleMapObjData.size())
247 {
248 deleteRoleMappingObject(asyncResp,
249 roleMapObjData.at(index).first,
250 serverType, index);
251 }
252 else
253 {
254 BMCWEB_LOG_ERROR << "Can't delete the object";
255 messages::propertyValueTypeError(
256 asyncResp->res, thisJson.dump(), "RemoteRoleMapping");
257 return;
258 }
259
260 index++;
261 continue;
262 }
263
264 if (thisJson.empty())
265 {
266 if ((input.size() > roleMapObjData.size()) &&
267 (index > roleMapObjData.size()))
268 {
269 BMCWEB_LOG_ERROR << "Empty object can't be inserted";
270 messages::propertyValueTypeError(
271 asyncResp->res, thisJson.dump(), "RemoteRoleMapping");
272 return;
273 }
274
275 index++;
276 continue;
277 }
278
279 const std::string* remoteGroup = nullptr;
280 nlohmann::json::const_iterator remoteGroupIt =
281 thisJson.find("RemoteGroup");
282
283 // extract "RemoteGroup" and "LocalRole" form JSON
284 if (remoteGroupIt != thisJson.end())
285 {
286 remoteGroup = remoteGroupIt->get_ptr<const std::string*>();
287 }
288
289 const std::string* localRole = nullptr;
290 nlohmann::json::const_iterator localRoleIt = thisJson.find("LocalRole");
291 if (localRoleIt != thisJson.end())
292 {
293 localRole = localRoleIt->get_ptr<const std::string*>();
294 }
295
296 // Update existing RoleMapping Object
297 if (roleMapObjData.size() >= input.size())
298 {
299 BMCWEB_LOG_DEBUG << "setRoleMappingProperties: Updating Object";
300 // If "RemoteGroup" info is provided
301 if (remoteGroup != nullptr)
302 {
303 if (remoteGroup->empty())
304 {
305 messages::propertyValueTypeError(
306 asyncResp->res, thisJson.dump(), "RemoteGroup");
307 return;
308 }
309 // check if the given data is not equal to already existing one
310 else if (roleMapObjData.at(index).second.groupName.compare(
311 *remoteGroup) != 0)
312 {
313 setRoleMappingProperty(asyncResp,
314 roleMapObjData.at(index).first,
315 "RemoteGroup", "GroupName",
316 *remoteGroup, serverType, index);
317 }
318 }
319
320 // If "LocalRole" info is provided
321 if (localRole != nullptr)
322 {
323 if (localRole->empty())
324 {
325 messages::propertyValueTypeError(
326 asyncResp->res, thisJson.dump(), "LocalRole");
327 return;
328 }
329 // check if the given data is not equal to already existing one
330 else if (roleMapObjData.at(index).second.privilege.compare(
331 *localRole) != 0)
332 {
333 setRoleMappingProperty(
334 asyncResp, roleMapObjData.at(index).first, "LocalRole",
335 "Privilege", *localRole, serverType, index);
336 }
337 }
338 index++;
339 }
340 // Create a new RoleMapping Object.
341 else
342 {
343 BMCWEB_LOG_DEBUG << "setRoleMappingProperties: Creating new Object";
344 if (localRole == nullptr || remoteGroup == nullptr)
345 {
346 messages::propertyValueTypeError(asyncResp->res,
347 thisJson.dump(),
348 "RemoteGroup or LocalRole");
349 return;
350 }
351 else if (remoteGroup->empty() || localRole->empty())
352 {
353 messages::propertyValueTypeError(
354 asyncResp->res, thisJson.dump(), "RemoteGroup LocalRole");
355 return;
356 }
357
358 std::string dbusObjectPath;
359 if (serverType == "ActiveDirectory")
360 {
361 dbusObjectPath = ADConfigObject;
362 }
363 else if (serverType == "LDAP")
364 {
365 dbusObjectPath = ldapConfigObject;
366 }
367
368 crow::connections::systemBus->async_method_call(
369 [asyncResp, serverType, index, localRole{std::move(*localRole)},
370 remoteGroup{std::move(*remoteGroup)}](
371 const boost::system::error_code ec) {
372 if (ec)
373 {
374 BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
375 messages::internalError(asyncResp->res);
376 }
377 nlohmann::json& remoteRoleJson =
378 asyncResp->res
379 .jsonValue[serverType]["RemoteRoleMapping"][index];
380 remoteRoleJson["LocalRole"] = localRole;
381 remoteRoleJson["RemoteGroup"] = remoteGroup;
382 },
383 ldapDbusService, dbusObjectPath, ldapPrivMapperInterface,
384 "Create", *remoteGroup, getPrivilegeFromRoleId(*localRole));
385 index++;
386 }
387 }
388}
389
390/**
Ratan Gupta6973a582018-12-13 18:25:44 +0530391 * Function that retrieves all properties for LDAP config object
392 * into JSON
393 */
394template <typename CallbackFunc>
395inline void getLDAPConfigData(const std::string& ldapType,
396 CallbackFunc&& callback)
397{
Ratan Guptaab828d72019-04-22 14:18:33 +0530398
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600399 const std::array<const char*, 2> interfaces = {ldapEnableInterface,
Ratan Gupta6973a582018-12-13 18:25:44 +0530400 ldapConfigInterface};
401
402 crow::connections::systemBus->async_method_call(
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600403 [callback, ldapType](const boost::system::error_code ec,
404 const GetObjectType& resp) {
405 LDAPConfigData confData{};
406 if (ec || resp.empty())
407 {
408 BMCWEB_LOG_ERROR << "DBUS response error during getting of "
409 "service name: "
410 << ec;
411 callback(false, confData, ldapType);
412 return;
413 }
414 std::string service = resp.begin()->first;
415 crow::connections::systemBus->async_method_call(
416 [callback, ldapType](const boost::system::error_code error_code,
417 const ManagedObjectType& ldapObjects) {
418 LDAPConfigData confData{};
419 if (error_code)
420 {
421 callback(false, confData, ldapType);
422 BMCWEB_LOG_ERROR << "D-Bus responses error: "
423 << error_code;
424 return;
425 }
426
427 std::string ldapDbusType;
428 std::string searchString;
429
430 if (ldapType == "LDAP")
431 {
432 ldapDbusType = "xyz.openbmc_project.User.Ldap.Config."
433 "Type.OpenLdap";
434 searchString = "openldap";
435 }
436 else if (ldapType == "ActiveDirectory")
437 {
438 ldapDbusType =
439 "xyz.openbmc_project.User.Ldap.Config.Type."
440 "ActiveDirectory";
441 searchString = "active_directory";
442 }
443 else
444 {
445 BMCWEB_LOG_ERROR
446 << "Can't get the DbusType for the given type="
447 << ldapType;
448 callback(false, confData, ldapType);
449 return;
450 }
451
452 std::string ldapEnableInterfaceStr = ldapEnableInterface;
453 std::string ldapConfigInterfaceStr = ldapConfigInterface;
454
455 for (const auto& object : ldapObjects)
456 {
457 // let's find the object whose ldap type is equal to the
458 // given type
459 if (object.first.str.find(searchString) ==
460 std::string::npos)
461 {
462 continue;
463 }
464
465 for (const auto& interface : object.second)
466 {
467 if (interface.first == ldapEnableInterfaceStr)
468 {
469 // rest of the properties are string.
470 for (const auto& property : interface.second)
471 {
472 if (property.first == "Enabled")
473 {
474 const bool* value =
475 std::get_if<bool>(&property.second);
476 if (value == nullptr)
477 {
478 continue;
479 }
480 confData.serviceEnabled = *value;
481 break;
482 }
483 }
484 }
485 else if (interface.first == ldapConfigInterfaceStr)
486 {
487
488 for (const auto& property : interface.second)
489 {
490 const std::string* value =
491 std::get_if<std::string>(
492 &property.second);
493 if (value == nullptr)
494 {
495 continue;
496 }
497 if (property.first == "LDAPServerURI")
498 {
499 confData.uri = *value;
500 }
501 else if (property.first == "LDAPBindDN")
502 {
503 confData.bindDN = *value;
504 }
505 else if (property.first == "LDAPBaseDN")
506 {
507 confData.baseDN = *value;
508 }
509 else if (property.first ==
510 "LDAPSearchScope")
511 {
512 confData.searchScope = *value;
513 }
514 else if (property.first ==
515 "GroupNameAttribute")
516 {
517 confData.groupAttribute = *value;
518 }
519 else if (property.first ==
520 "UserNameAttribute")
521 {
522 confData.userNameAttribute = *value;
523 }
524 else if (property.first == "LDAPType")
525 {
526 confData.serverType = *value;
527 }
528 }
529 }
530 else if (interface.first ==
531 "xyz.openbmc_project.User."
532 "PrivilegeMapperEntry")
533 {
534 LDAPRoleMapData roleMapData{};
535 for (const auto& property : interface.second)
536 {
537 const std::string* value =
538 std::get_if<std::string>(
539 &property.second);
540
541 if (value == nullptr)
542 {
543 continue;
544 }
545
546 if (property.first == "GroupName")
547 {
548 roleMapData.groupName = *value;
549 }
550 else if (property.first == "Privilege")
551 {
552 roleMapData.privilege = *value;
553 }
554 }
555
556 confData.groupRoleList.push_back(std::make_pair(
557 object.first.str, roleMapData));
558 }
559 }
560 }
561 callback(true, confData, ldapType);
562 },
563 service, ldapRootObject, dbusObjManagerIntf,
564 "GetManagedObjects");
565 },
566 mapperBusName, mapperObjectPath, mapperIntf, "GetObject",
567 ldapConfigObject, interfaces);
Ratan Gupta6973a582018-12-13 18:25:44 +0530568}
569
Ed Tanous1abe55e2018-09-05 08:30:59 -0700570class AccountService : public Node
571{
572 public:
573 AccountService(CrowApp& app) : Node(app, "/redfish/v1/AccountService/")
574 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700575 entityPrivileges = {
576 {boost::beast::http::verb::get,
577 {{"ConfigureUsers"}, {"ConfigureManager"}}},
578 {boost::beast::http::verb::head, {{"Login"}}},
579 {boost::beast::http::verb::patch, {{"ConfigureUsers"}}},
580 {boost::beast::http::verb::put, {{"ConfigureUsers"}}},
581 {boost::beast::http::verb::delete_, {{"ConfigureUsers"}}},
582 {boost::beast::http::verb::post, {{"ConfigureUsers"}}}};
583 }
Lewanczyk, Dawid88d16c92018-02-02 14:51:09 +0100584
Ed Tanous1abe55e2018-09-05 08:30:59 -0700585 private:
Ratan Gupta8a07d282019-03-16 08:33:47 +0530586 /**
587 * @brief parses the authentication section under the LDAP
588 * @param input JSON data
589 * @param asyncResp pointer to the JSON response
590 * @param userName userName to be filled from the given JSON.
591 * @param password password to be filled from the given JSON.
592 */
593 void
594 parseLDAPAuthenticationJson(nlohmann::json input,
595 const std::shared_ptr<AsyncResp>& asyncResp,
596 std::optional<std::string>& username,
597 std::optional<std::string>& password)
598 {
599 std::optional<std::string> authType;
600
601 if (!json_util::readJson(input, asyncResp->res, "AuthenticationType",
602 authType, "Username", username, "Password",
603 password))
604 {
605 return;
606 }
607 if (!authType)
608 {
609 return;
610 }
611 if (*authType != "UsernameAndPassword")
612 {
613 messages::propertyValueNotInList(asyncResp->res, *authType,
614 "AuthenticationType");
615 return;
616 }
617 }
618 /**
619 * @brief parses the LDAPService section under the LDAP
620 * @param input JSON data
621 * @param asyncResp pointer to the JSON response
622 * @param baseDNList baseDN to be filled from the given JSON.
623 * @param userNameAttribute userName to be filled from the given JSON.
624 * @param groupaAttribute password to be filled from the given JSON.
625 */
626
627 void parseLDAPServiceJson(
628 nlohmann::json input, const std::shared_ptr<AsyncResp>& asyncResp,
629 std::optional<std::vector<std::string>>& baseDNList,
630 std::optional<std::string>& userNameAttribute,
631 std::optional<std::string>& groupsAttribute)
632 {
633 std::optional<nlohmann::json> searchSettings;
634
635 if (!json_util::readJson(input, asyncResp->res, "SearchSettings",
636 searchSettings))
637 {
638 return;
639 }
640 if (!searchSettings)
641 {
642 return;
643 }
644 if (!json_util::readJson(*searchSettings, asyncResp->res,
645 "BaseDistinguishedNames", baseDNList,
646 "UsernameAttribute", userNameAttribute,
647 "GroupsAttribute", groupsAttribute))
648 {
649 return;
650 }
651 }
652 /**
653 * @brief updates the LDAP server address and updates the
654 json response with the new value.
655 * @param serviceAddressList address to be updated.
656 * @param asyncResp pointer to the JSON response
657 * @param ldapServerElementName Type of LDAP
658 server(openLDAP/ActiveDirectory)
659 */
660
661 void handleServiceAddressPatch(
662 const std::vector<std::string>& serviceAddressList,
663 const std::shared_ptr<AsyncResp>& asyncResp,
664 const std::string& ldapServerElementName,
665 const std::string& ldapConfigObject)
666 {
667 crow::connections::systemBus->async_method_call(
668 [asyncResp, ldapServerElementName,
669 serviceAddressList](const boost::system::error_code ec) {
670 if (ec)
671 {
672 BMCWEB_LOG_DEBUG
673 << "Error Occured in updating the service address";
674 messages::internalError(asyncResp->res);
675 return;
676 }
677 std::vector<std::string> modifiedserviceAddressList = {
678 serviceAddressList.front()};
679 asyncResp->res
680 .jsonValue[ldapServerElementName]["ServiceAddresses"] =
681 modifiedserviceAddressList;
682 if ((serviceAddressList).size() > 1)
683 {
684 messages::propertyValueModified(asyncResp->res,
685 "ServiceAddresses",
686 serviceAddressList.front());
687 }
688 BMCWEB_LOG_DEBUG << "Updated the service address";
689 },
690 ldapDbusService, ldapConfigObject, propertyInterface, "Set",
691 ldapConfigInterface, "LDAPServerURI",
692 std::variant<std::string>(serviceAddressList.front()));
693 }
694 /**
695 * @brief updates the LDAP Bind DN and updates the
696 json response with the new value.
697 * @param username name of the user which needs to be updated.
698 * @param asyncResp pointer to the JSON response
699 * @param ldapServerElementName Type of LDAP
700 server(openLDAP/ActiveDirectory)
701 */
702
703 void handleUserNamePatch(const std::string& username,
704 const std::shared_ptr<AsyncResp>& asyncResp,
705 const std::string& ldapServerElementName,
706 const std::string& ldapConfigObject)
707 {
708 crow::connections::systemBus->async_method_call(
709 [asyncResp, username,
710 ldapServerElementName](const boost::system::error_code ec) {
711 if (ec)
712 {
713 BMCWEB_LOG_DEBUG
714 << "Error occured in updating the username";
715 messages::internalError(asyncResp->res);
716 return;
717 }
718 asyncResp->res.jsonValue[ldapServerElementName]
719 ["Authentication"]["Username"] =
720 username;
721 BMCWEB_LOG_DEBUG << "Updated the username";
722 },
723 ldapDbusService, ldapConfigObject, propertyInterface, "Set",
724 ldapConfigInterface, "LDAPBindDN",
725 std::variant<std::string>(username));
726 }
727
728 /**
729 * @brief updates the LDAP password
730 * @param password : ldap password which needs to be updated.
731 * @param asyncResp pointer to the JSON response
732 * @param ldapServerElementName Type of LDAP
733 * server(openLDAP/ActiveDirectory)
734 */
735
736 void handlePasswordPatch(const std::string& password,
737 const std::shared_ptr<AsyncResp>& asyncResp,
738 const std::string& ldapServerElementName,
739 const std::string& ldapConfigObject)
740 {
741 crow::connections::systemBus->async_method_call(
742 [asyncResp, password,
743 ldapServerElementName](const boost::system::error_code ec) {
744 if (ec)
745 {
746 BMCWEB_LOG_DEBUG
747 << "Error occured in updating the password";
748 messages::internalError(asyncResp->res);
749 return;
750 }
751 asyncResp->res.jsonValue[ldapServerElementName]
752 ["Authentication"]["Password"] = "";
753 BMCWEB_LOG_DEBUG << "Updated the password";
754 },
755 ldapDbusService, ldapConfigObject, propertyInterface, "Set",
756 ldapConfigInterface, "LDAPBindDNPassword",
757 std::variant<std::string>(password));
758 }
759
760 /**
761 * @brief updates the LDAP BaseDN and updates the
762 json response with the new value.
763 * @param baseDNList baseDN list which needs to be updated.
764 * @param asyncResp pointer to the JSON response
765 * @param ldapServerElementName Type of LDAP
766 server(openLDAP/ActiveDirectory)
767 */
768
769 void handleBaseDNPatch(const std::vector<std::string>& baseDNList,
770 const std::shared_ptr<AsyncResp>& asyncResp,
771 const std::string& ldapServerElementName,
772 const std::string& ldapConfigObject)
773 {
774 crow::connections::systemBus->async_method_call(
775 [asyncResp, baseDNList,
776 ldapServerElementName](const boost::system::error_code ec) {
777 if (ec)
778 {
779 BMCWEB_LOG_DEBUG << "Error Occured in Updating the base DN";
780 messages::internalError(asyncResp->res);
781 return;
782 }
783 auto& serverTypeJson =
784 asyncResp->res.jsonValue[ldapServerElementName];
785 auto& searchSettingsJson =
786 serverTypeJson["LDAPService"]["SearchSettings"];
787 std::vector<std::string> modifiedBaseDNList = {
788 baseDNList.front()};
789 searchSettingsJson["BaseDistinguishedNames"] =
790 modifiedBaseDNList;
791 if (baseDNList.size() > 1)
792 {
793 messages::propertyValueModified(asyncResp->res,
794 "BaseDistinguishedNames",
795 baseDNList.front());
796 }
797 BMCWEB_LOG_DEBUG << "Updated the base DN";
798 },
799 ldapDbusService, ldapConfigObject, propertyInterface, "Set",
800 ldapConfigInterface, "LDAPBaseDN",
801 std::variant<std::string>(baseDNList.front()));
802 }
803 /**
804 * @brief updates the LDAP user name attribute and updates the
805 json response with the new value.
806 * @param userNameAttribute attribute to be updated.
807 * @param asyncResp pointer to the JSON response
808 * @param ldapServerElementName Type of LDAP
809 server(openLDAP/ActiveDirectory)
810 */
811
812 void handleUserNameAttrPatch(const std::string& userNameAttribute,
813 const std::shared_ptr<AsyncResp>& asyncResp,
814 const std::string& ldapServerElementName,
815 const std::string& ldapConfigObject)
816 {
817 crow::connections::systemBus->async_method_call(
818 [asyncResp, userNameAttribute,
819 ldapServerElementName](const boost::system::error_code ec) {
820 if (ec)
821 {
822 BMCWEB_LOG_DEBUG << "Error Occured in Updating the "
823 "username attribute";
824 messages::internalError(asyncResp->res);
825 return;
826 }
827 auto& serverTypeJson =
828 asyncResp->res.jsonValue[ldapServerElementName];
829 auto& searchSettingsJson =
830 serverTypeJson["LDAPService"]["SearchSettings"];
831 searchSettingsJson["UsernameAttribute"] = userNameAttribute;
832 BMCWEB_LOG_DEBUG << "Updated the user name attr.";
833 },
834 ldapDbusService, ldapConfigObject, propertyInterface, "Set",
835 ldapConfigInterface, "UserNameAttribute",
836 std::variant<std::string>(userNameAttribute));
837 }
838 /**
839 * @brief updates the LDAP group attribute and updates the
840 json response with the new value.
841 * @param groupsAttribute attribute to be updated.
842 * @param asyncResp pointer to the JSON response
843 * @param ldapServerElementName Type of LDAP
844 server(openLDAP/ActiveDirectory)
845 */
846
847 void handleGroupNameAttrPatch(const std::string& groupsAttribute,
848 const std::shared_ptr<AsyncResp>& asyncResp,
849 const std::string& ldapServerElementName,
850 const std::string& ldapConfigObject)
851 {
852 crow::connections::systemBus->async_method_call(
853 [asyncResp, groupsAttribute,
854 ldapServerElementName](const boost::system::error_code ec) {
855 if (ec)
856 {
857 BMCWEB_LOG_DEBUG << "Error Occured in Updating the "
858 "groupname attribute";
859 messages::internalError(asyncResp->res);
860 return;
861 }
862 auto& serverTypeJson =
863 asyncResp->res.jsonValue[ldapServerElementName];
864 auto& searchSettingsJson =
865 serverTypeJson["LDAPService"]["SearchSettings"];
866 searchSettingsJson["GroupsAttribute"] = groupsAttribute;
867 BMCWEB_LOG_DEBUG << "Updated the groupname attr";
868 },
869 ldapDbusService, ldapConfigObject, propertyInterface, "Set",
870 ldapConfigInterface, "GroupNameAttribute",
871 std::variant<std::string>(groupsAttribute));
872 }
873 /**
874 * @brief updates the LDAP service enable and updates the
875 json response with the new value.
876 * @param input JSON data.
877 * @param asyncResp pointer to the JSON response
878 * @param ldapServerElementName Type of LDAP
879 server(openLDAP/ActiveDirectory)
880 */
881
882 void handleServiceEnablePatch(bool serviceEnabled,
883 const std::shared_ptr<AsyncResp>& asyncResp,
884 const std::string& ldapServerElementName,
885 const std::string& ldapConfigObject)
886 {
887 crow::connections::systemBus->async_method_call(
888 [asyncResp, serviceEnabled,
889 ldapServerElementName](const boost::system::error_code ec) {
890 if (ec)
891 {
892 BMCWEB_LOG_DEBUG
893 << "Error Occured in Updating the service enable";
894 messages::internalError(asyncResp->res);
895 return;
896 }
897 asyncResp->res
898 .jsonValue[ldapServerElementName]["ServiceEnabled"] =
899 serviceEnabled;
900 BMCWEB_LOG_DEBUG << "Updated Service enable = "
901 << serviceEnabled;
902 },
903 ldapDbusService, ldapConfigObject, propertyInterface, "Set",
904 ldapEnableInterface, "Enabled", std::variant<bool>(serviceEnabled));
905 }
906
907 /**
908 * @brief Get the required values from the given JSON, validates the
909 * value and create the LDAP config object.
910 * @param input JSON data
911 * @param asyncResp pointer to the JSON response
912 * @param serverType Type of LDAP server(openLDAP/ActiveDirectory)
913 */
914
915 void handleLDAPPatch(nlohmann::json& input,
916 const std::shared_ptr<AsyncResp>& asyncResp,
917 const crow::Request& req,
918 const std::vector<std::string>& params,
919 const std::string& serverType)
920 {
Ratan Guptaeb2bbe52019-04-22 14:27:01 +0530921 std::string dbusObjectPath;
922 if (serverType == "ActiveDirectory")
923 {
924 dbusObjectPath = ADConfigObject;
925 }
926 else if (serverType == "LDAP")
927 {
928 dbusObjectPath = ldapConfigObject;
929 }
930
Ratan Gupta8a07d282019-03-16 08:33:47 +0530931 std::optional<nlohmann::json> authentication;
932 std::optional<nlohmann::json> ldapService;
933 std::optional<std::string> accountProviderType;
934 std::optional<std::vector<std::string>> serviceAddressList;
935 std::optional<bool> serviceEnabled;
936 std::optional<std::vector<std::string>> baseDNList;
937 std::optional<std::string> userNameAttribute;
938 std::optional<std::string> groupsAttribute;
939 std::optional<std::string> userName;
940 std::optional<std::string> password;
Nagaraju Goruganti2a21b9d2019-01-31 05:24:27 -0600941 std::optional<nlohmann::json> remoteRoleMapData;
Ratan Gupta8a07d282019-03-16 08:33:47 +0530942
943 if (!json_util::readJson(input, asyncResp->res, "Authentication",
944 authentication, "LDAPService", ldapService,
945 "ServiceAddresses", serviceAddressList,
946 "AccountProviderType", accountProviderType,
Nagaraju Goruganti2a21b9d2019-01-31 05:24:27 -0600947 "ServiceEnabled", serviceEnabled,
948 "RemoteRoleMapping", remoteRoleMapData))
Ratan Gupta8a07d282019-03-16 08:33:47 +0530949 {
950 return;
951 }
952
953 if (authentication)
954 {
955 parseLDAPAuthenticationJson(*authentication, asyncResp, userName,
956 password);
957 }
958 if (ldapService)
959 {
960 parseLDAPServiceJson(*ldapService, asyncResp, baseDNList,
961 userNameAttribute, groupsAttribute);
962 }
963 if (accountProviderType)
964 {
965 messages::propertyNotWritable(asyncResp->res,
966 "AccountProviderType");
967 }
968 if (serviceAddressList)
969 {
970 if ((*serviceAddressList).size() == 0)
971 {
972 messages::propertyValueNotInList(asyncResp->res, "[]",
973 "ServiceAddress");
974 return;
975 }
976 }
977 if (baseDNList)
978 {
979 if ((*baseDNList).size() == 0)
980 {
981 messages::propertyValueNotInList(asyncResp->res, "[]",
982 "BaseDistinguishedNames");
983 return;
984 }
985 }
986
987 // nothing to update, then return
988 if (!userName && !password && !serviceAddressList && !baseDNList &&
Nagaraju Goruganti2a21b9d2019-01-31 05:24:27 -0600989 !userNameAttribute && !groupsAttribute && !serviceEnabled &&
990 !remoteRoleMapData)
Ratan Gupta8a07d282019-03-16 08:33:47 +0530991 {
992 return;
993 }
994
995 // Get the existing resource first then keep modifying
996 // whenever any property gets updated.
Ratan Guptaab828d72019-04-22 14:18:33 +0530997 getLDAPConfigData(serverType, [this, asyncResp, userName, password,
998 baseDNList, userNameAttribute,
999 groupsAttribute, accountProviderType,
Ratan Guptaeb2bbe52019-04-22 14:27:01 +05301000 serviceAddressList, serviceEnabled,
Nagaraju Goruganti2a21b9d2019-01-31 05:24:27 -06001001 dbusObjectPath, remoteRoleMapData](
Ratan Guptaab828d72019-04-22 14:18:33 +05301002 bool success, LDAPConfigData confData,
1003 const std::string& serverType) {
1004 if (!success)
1005 {
1006 messages::internalError(asyncResp->res);
1007 return;
1008 }
1009 parseLDAPConfigData(asyncResp->res.jsonValue, confData, serverType);
1010 if (confData.serviceEnabled)
1011 {
1012 // Disable the service first and update the rest of
1013 // the properties.
1014 handleServiceEnablePatch(false, asyncResp, serverType,
Ratan Guptaeb2bbe52019-04-22 14:27:01 +05301015 dbusObjectPath);
Ratan Guptaab828d72019-04-22 14:18:33 +05301016 }
Ratan Gupta8a07d282019-03-16 08:33:47 +05301017
Ratan Guptaab828d72019-04-22 14:18:33 +05301018 if (serviceAddressList)
1019 {
1020 handleServiceAddressPatch(*serviceAddressList, asyncResp,
Ratan Guptaeb2bbe52019-04-22 14:27:01 +05301021 serverType, dbusObjectPath);
Ratan Guptaab828d72019-04-22 14:18:33 +05301022 }
1023 if (userName)
1024 {
1025 handleUserNamePatch(*userName, asyncResp, serverType,
Ratan Guptaeb2bbe52019-04-22 14:27:01 +05301026 dbusObjectPath);
Ratan Guptaab828d72019-04-22 14:18:33 +05301027 }
1028 if (password)
1029 {
1030 handlePasswordPatch(*password, asyncResp, serverType,
Ratan Guptaeb2bbe52019-04-22 14:27:01 +05301031 dbusObjectPath);
Ratan Guptaab828d72019-04-22 14:18:33 +05301032 }
Ratan Gupta8a07d282019-03-16 08:33:47 +05301033
Ratan Guptaab828d72019-04-22 14:18:33 +05301034 if (baseDNList)
1035 {
1036 handleBaseDNPatch(*baseDNList, asyncResp, serverType,
Ratan Guptaeb2bbe52019-04-22 14:27:01 +05301037 dbusObjectPath);
Ratan Guptaab828d72019-04-22 14:18:33 +05301038 }
1039 if (userNameAttribute)
1040 {
1041 handleUserNameAttrPatch(*userNameAttribute, asyncResp,
Ratan Guptaeb2bbe52019-04-22 14:27:01 +05301042 serverType, dbusObjectPath);
Ratan Guptaab828d72019-04-22 14:18:33 +05301043 }
1044 if (groupsAttribute)
1045 {
1046 handleGroupNameAttrPatch(*groupsAttribute, asyncResp,
Ratan Guptaeb2bbe52019-04-22 14:27:01 +05301047 serverType, dbusObjectPath);
Ratan Guptaab828d72019-04-22 14:18:33 +05301048 }
1049 if (serviceEnabled)
1050 {
1051 // if user has given the value as true then enable
1052 // the service. if user has given false then no-op
1053 // as service is already stopped.
1054 if (*serviceEnabled)
Ratan Gupta8a07d282019-03-16 08:33:47 +05301055 {
Ratan Guptaab828d72019-04-22 14:18:33 +05301056 handleServiceEnablePatch(*serviceEnabled, asyncResp,
Ratan Guptaeb2bbe52019-04-22 14:27:01 +05301057 serverType, dbusObjectPath);
Ratan Gupta8a07d282019-03-16 08:33:47 +05301058 }
Ratan Guptaab828d72019-04-22 14:18:33 +05301059 }
1060 else
1061 {
1062 // if user has not given the service enabled value
1063 // then revert it to the same state as it was
1064 // before.
1065 handleServiceEnablePatch(confData.serviceEnabled, asyncResp,
Ratan Guptaeb2bbe52019-04-22 14:27:01 +05301066 serverType, dbusObjectPath);
Ratan Guptaab828d72019-04-22 14:18:33 +05301067 }
Nagaraju Goruganti2a21b9d2019-01-31 05:24:27 -06001068
1069 if (remoteRoleMapData)
1070 {
1071
1072 handleRoleMapPatch(asyncResp, confData.groupRoleList,
1073 serverType, *remoteRoleMapData);
1074 }
Ratan Guptaab828d72019-04-22 14:18:33 +05301075 });
Ratan Gupta8a07d282019-03-16 08:33:47 +05301076 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001077 void doGet(crow::Response& res, const crow::Request& req,
1078 const std::vector<std::string>& params) override
1079 {
AppaRao Puli3d958bb2018-12-25 12:45:54 +05301080 auto asyncResp = std::make_shared<AsyncResp>(res);
1081 res.jsonValue = {
1082 {"@odata.context", "/redfish/v1/"
1083 "$metadata#AccountService.AccountService"},
1084 {"@odata.id", "/redfish/v1/AccountService"},
1085 {"@odata.type", "#AccountService."
Marri Devender Rao37cce912019-02-20 01:05:22 -06001086 "v1_4_0.AccountService"},
AppaRao Puli3d958bb2018-12-25 12:45:54 +05301087 {"Id", "AccountService"},
1088 {"Name", "Account Service"},
1089 {"Description", "Account Service"},
1090 {"ServiceEnabled", true},
AppaRao Puli343ff2e2019-03-24 00:42:13 +05301091 {"MaxPasswordLength", 20},
AppaRao Puli3d958bb2018-12-25 12:45:54 +05301092 {"Accounts",
1093 {{"@odata.id", "/redfish/v1/AccountService/Accounts"}}},
Marri Devender Rao37cce912019-02-20 01:05:22 -06001094 {"Roles", {{"@odata.id", "/redfish/v1/AccountService/Roles"}}},
1095 {"LDAP",
1096 {{"Certificates",
1097 {{"@odata.id",
1098 "/redfish/v1/AccountService/LDAP/Certificates"}}}}}};
AppaRao Puli3d958bb2018-12-25 12:45:54 +05301099 crow::connections::systemBus->async_method_call(
1100 [asyncResp](
1101 const boost::system::error_code ec,
1102 const std::vector<std::pair<
Ed Tanousabf2add2019-01-22 16:40:12 -08001103 std::string, std::variant<uint32_t, uint16_t, uint8_t>>>&
AppaRao Puli3d958bb2018-12-25 12:45:54 +05301104 propertiesList) {
1105 if (ec)
1106 {
1107 messages::internalError(asyncResp->res);
1108 return;
1109 }
1110 BMCWEB_LOG_DEBUG << "Got " << propertiesList.size()
1111 << "properties for AccountService";
1112 for (const std::pair<std::string,
Ed Tanousabf2add2019-01-22 16:40:12 -08001113 std::variant<uint32_t, uint16_t, uint8_t>>&
AppaRao Puli3d958bb2018-12-25 12:45:54 +05301114 property : propertiesList)
1115 {
1116 if (property.first == "MinPasswordLength")
1117 {
1118 const uint8_t* value =
Ed Tanousabf2add2019-01-22 16:40:12 -08001119 std::get_if<uint8_t>(&property.second);
AppaRao Puli3d958bb2018-12-25 12:45:54 +05301120 if (value != nullptr)
1121 {
1122 asyncResp->res.jsonValue["MinPasswordLength"] =
1123 *value;
1124 }
1125 }
1126 if (property.first == "AccountUnlockTimeout")
1127 {
1128 const uint32_t* value =
Ed Tanousabf2add2019-01-22 16:40:12 -08001129 std::get_if<uint32_t>(&property.second);
AppaRao Puli3d958bb2018-12-25 12:45:54 +05301130 if (value != nullptr)
1131 {
1132 asyncResp->res.jsonValue["AccountLockoutDuration"] =
1133 *value;
1134 }
1135 }
1136 if (property.first == "MaxLoginAttemptBeforeLockout")
1137 {
1138 const uint16_t* value =
Ed Tanousabf2add2019-01-22 16:40:12 -08001139 std::get_if<uint16_t>(&property.second);
AppaRao Puli3d958bb2018-12-25 12:45:54 +05301140 if (value != nullptr)
1141 {
1142 asyncResp->res
1143 .jsonValue["AccountLockoutThreshold"] = *value;
1144 }
1145 }
1146 }
1147 },
1148 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
1149 "org.freedesktop.DBus.Properties", "GetAll",
1150 "xyz.openbmc_project.User.AccountPolicy");
Ratan Gupta6973a582018-12-13 18:25:44 +05301151
Ratan Guptaab828d72019-04-22 14:18:33 +05301152 auto callback = [asyncResp](bool success, LDAPConfigData& confData,
1153 const std::string& ldapType) {
1154 parseLDAPConfigData(asyncResp->res.jsonValue, confData, ldapType);
1155 };
1156
1157 getLDAPConfigData("LDAP", callback);
1158 getLDAPConfigData("ActiveDirectory", callback);
AppaRao Puli3d958bb2018-12-25 12:45:54 +05301159 }
Ratan Gupta6973a582018-12-13 18:25:44 +05301160
AppaRao Puli3d958bb2018-12-25 12:45:54 +05301161 void doPatch(crow::Response& res, const crow::Request& req,
1162 const std::vector<std::string>& params) override
1163 {
1164 auto asyncResp = std::make_shared<AsyncResp>(res);
1165
1166 std::optional<uint32_t> unlockTimeout;
1167 std::optional<uint16_t> lockoutThreshold;
Ratan Gupta19fb6e72019-03-04 13:30:50 +05301168 std::optional<uint16_t> minPasswordLength;
1169 std::optional<uint16_t> maxPasswordLength;
Ratan Gupta8a07d282019-03-16 08:33:47 +05301170 std::optional<nlohmann::json> ldapObject;
Ratan Guptaeb2bbe52019-04-22 14:27:01 +05301171 std::optional<nlohmann::json> activeDirectoryObject;
Ratan Gupta19fb6e72019-03-04 13:30:50 +05301172
AppaRao Puli3d958bb2018-12-25 12:45:54 +05301173 if (!json_util::readJson(req, res, "AccountLockoutDuration",
1174 unlockTimeout, "AccountLockoutThreshold",
Ratan Gupta19fb6e72019-03-04 13:30:50 +05301175 lockoutThreshold, "MaxPasswordLength",
1176 maxPasswordLength, "MinPasswordLength",
Ratan Guptaeb2bbe52019-04-22 14:27:01 +05301177 minPasswordLength, "LDAP", ldapObject,
1178 "ActiveDirectory", activeDirectoryObject))
AppaRao Puli3d958bb2018-12-25 12:45:54 +05301179 {
1180 return;
1181 }
Ratan Gupta19fb6e72019-03-04 13:30:50 +05301182
1183 if (minPasswordLength)
1184 {
1185 messages::propertyNotWritable(asyncResp->res, "MinPasswordLength");
1186 }
1187
1188 if (maxPasswordLength)
1189 {
1190 messages::propertyNotWritable(asyncResp->res, "MaxPasswordLength");
1191 }
1192
Ratan Gupta8a07d282019-03-16 08:33:47 +05301193 if (ldapObject)
1194 {
1195 handleLDAPPatch(*ldapObject, asyncResp, req, params, "LDAP");
1196 }
1197
Ratan Guptaeb2bbe52019-04-22 14:27:01 +05301198 if (activeDirectoryObject)
1199 {
1200 handleLDAPPatch(*activeDirectoryObject, asyncResp, req, params,
1201 "ActiveDirectory");
1202 }
1203
AppaRao Puli3d958bb2018-12-25 12:45:54 +05301204 if (unlockTimeout)
1205 {
1206 crow::connections::systemBus->async_method_call(
1207 [asyncResp](const boost::system::error_code ec) {
1208 if (ec)
1209 {
1210 messages::internalError(asyncResp->res);
1211 return;
1212 }
Ratan Guptaadd61332019-02-13 20:49:16 +05301213 messages::success(asyncResp->res);
AppaRao Puli3d958bb2018-12-25 12:45:54 +05301214 },
1215 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
1216 "org.freedesktop.DBus.Properties", "Set",
1217 "xyz.openbmc_project.User.AccountPolicy",
Ed Tanousabf2add2019-01-22 16:40:12 -08001218 "AccountUnlockTimeout", std::variant<uint32_t>(*unlockTimeout));
AppaRao Puli3d958bb2018-12-25 12:45:54 +05301219 }
1220 if (lockoutThreshold)
1221 {
1222 crow::connections::systemBus->async_method_call(
1223 [asyncResp](const boost::system::error_code ec) {
1224 if (ec)
1225 {
1226 messages::internalError(asyncResp->res);
1227 return;
1228 }
Ratan Guptaadd61332019-02-13 20:49:16 +05301229 messages::success(asyncResp->res);
AppaRao Puli3d958bb2018-12-25 12:45:54 +05301230 },
1231 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
1232 "org.freedesktop.DBus.Properties", "Set",
1233 "xyz.openbmc_project.User.AccountPolicy",
1234 "MaxLoginAttemptBeforeLockout",
Ed Tanousabf2add2019-01-22 16:40:12 -08001235 std::variant<uint16_t>(*lockoutThreshold));
AppaRao Puli3d958bb2018-12-25 12:45:54 +05301236 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001237 }
Lewanczyk, Dawid88d16c92018-02-02 14:51:09 +01001238};
Tanousf00032d2018-11-05 01:18:10 -03001239
Ed Tanousb9b2e0b2018-09-13 13:47:50 -07001240class AccountsCollection : public Node
1241{
1242 public:
1243 AccountsCollection(CrowApp& app) :
1244 Node(app, "/redfish/v1/AccountService/Accounts/")
1245 {
Ed Tanousb9b2e0b2018-09-13 13:47:50 -07001246 entityPrivileges = {
1247 {boost::beast::http::verb::get,
1248 {{"ConfigureUsers"}, {"ConfigureManager"}}},
1249 {boost::beast::http::verb::head, {{"Login"}}},
1250 {boost::beast::http::verb::patch, {{"ConfigureUsers"}}},
1251 {boost::beast::http::verb::put, {{"ConfigureUsers"}}},
1252 {boost::beast::http::verb::delete_, {{"ConfigureUsers"}}},
1253 {boost::beast::http::verb::post, {{"ConfigureUsers"}}}};
1254 }
1255
1256 private:
1257 void doGet(crow::Response& res, const crow::Request& req,
1258 const std::vector<std::string>& params) override
1259 {
Ed Tanousb9b2e0b2018-09-13 13:47:50 -07001260 auto asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous0f74e642018-11-12 15:17:05 -08001261 res.jsonValue = {{"@odata.context",
1262 "/redfish/v1/"
1263 "$metadata#ManagerAccountCollection."
1264 "ManagerAccountCollection"},
1265 {"@odata.id", "/redfish/v1/AccountService/Accounts"},
1266 {"@odata.type", "#ManagerAccountCollection."
1267 "ManagerAccountCollection"},
1268 {"Name", "Accounts Collection"},
1269 {"Description", "BMC User Accounts"}};
1270
Ed Tanousb9b2e0b2018-09-13 13:47:50 -07001271 crow::connections::systemBus->async_method_call(
1272 [asyncResp](const boost::system::error_code ec,
1273 const ManagedObjectType& users) {
1274 if (ec)
1275 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001276 messages::internalError(asyncResp->res);
Ed Tanousb9b2e0b2018-09-13 13:47:50 -07001277 return;
1278 }
1279
1280 nlohmann::json& memberArray =
1281 asyncResp->res.jsonValue["Members"];
1282 memberArray = nlohmann::json::array();
1283
1284 asyncResp->res.jsonValue["Members@odata.count"] = users.size();
1285 for (auto& user : users)
1286 {
1287 const std::string& path =
1288 static_cast<const std::string&>(user.first);
1289 std::size_t lastIndex = path.rfind("/");
1290 if (lastIndex == std::string::npos)
1291 {
1292 lastIndex = 0;
1293 }
1294 else
1295 {
1296 lastIndex += 1;
1297 }
1298 memberArray.push_back(
1299 {{"@odata.id", "/redfish/v1/AccountService/Accounts/" +
1300 path.substr(lastIndex)}});
1301 }
1302 },
1303 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
1304 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
1305 }
Ed Tanous04ae99e2018-09-20 15:54:36 -07001306 void doPost(crow::Response& res, const crow::Request& req,
1307 const std::vector<std::string>& params) override
1308 {
1309 auto asyncResp = std::make_shared<AsyncResp>(res);
1310
Ed Tanous9712f8a2018-09-21 13:38:49 -07001311 std::string username;
1312 std::string password;
Ed Tanousa24526d2018-12-10 15:17:59 -08001313 std::optional<std::string> roleId("User");
1314 std::optional<bool> enabled = true;
Ed Tanous9712f8a2018-09-21 13:38:49 -07001315 if (!json_util::readJson(req, res, "UserName", username, "Password",
1316 password, "RoleId", roleId, "Enabled",
1317 enabled))
Ed Tanous04ae99e2018-09-20 15:54:36 -07001318 {
1319 return;
1320 }
1321
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -06001322 std::string priv = getPrivilegeFromRoleId(*roleId);
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301323 if (priv.empty())
Ed Tanous04ae99e2018-09-20 15:54:36 -07001324 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001325 messages::propertyValueNotInList(asyncResp->res, *roleId, "RoleId");
Ed Tanous04ae99e2018-09-20 15:54:36 -07001326 return;
1327 }
Ed Tanous9712f8a2018-09-21 13:38:49 -07001328 roleId = priv;
Ed Tanous04ae99e2018-09-20 15:54:36 -07001329
1330 crow::connections::systemBus->async_method_call(
Ed Tanous9712f8a2018-09-21 13:38:49 -07001331 [asyncResp, username, password{std::move(password)}](
Ed Tanous04ae99e2018-09-20 15:54:36 -07001332 const boost::system::error_code ec) {
1333 if (ec)
1334 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001335 messages::resourceAlreadyExists(
1336 asyncResp->res, "#ManagerAccount.v1_0_3.ManagerAccount",
1337 "UserName", username);
Ed Tanous04ae99e2018-09-20 15:54:36 -07001338 return;
1339 }
1340
1341 if (!pamUpdatePassword(username, password))
1342 {
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -06001343 // At this point we have a user that's been created, but
1344 // the password set failed. Something is wrong, so
1345 // delete the user that we've already created
Ed Tanous04ae99e2018-09-20 15:54:36 -07001346 crow::connections::systemBus->async_method_call(
1347 [asyncResp](const boost::system::error_code ec) {
1348 if (ec)
1349 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001350 messages::internalError(asyncResp->res);
Ed Tanous04ae99e2018-09-20 15:54:36 -07001351 return;
1352 }
1353
Jason M. Billsf12894f2018-10-09 12:45:45 -07001354 messages::invalidObject(asyncResp->res, "Password");
Ed Tanous04ae99e2018-09-20 15:54:36 -07001355 },
1356 "xyz.openbmc_project.User.Manager",
1357 "/xyz/openbmc_project/user/" + username,
1358 "xyz.openbmc_project.Object.Delete", "Delete");
1359
1360 BMCWEB_LOG_ERROR << "pamUpdatePassword Failed";
1361 return;
1362 }
1363
Jason M. Billsf12894f2018-10-09 12:45:45 -07001364 messages::created(asyncResp->res);
Ed Tanous04ae99e2018-09-20 15:54:36 -07001365 asyncResp->res.addHeader(
1366 "Location",
1367 "/redfish/v1/AccountService/Accounts/" + username);
1368 },
1369 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
Ed Tanous9712f8a2018-09-21 13:38:49 -07001370 "xyz.openbmc_project.User.Manager", "CreateUser", username,
Ed Tanous04ae99e2018-09-20 15:54:36 -07001371 std::array<const char*, 4>{"ipmi", "redfish", "ssh", "web"},
Ed Tanous9712f8a2018-09-21 13:38:49 -07001372 *roleId, *enabled);
Ed Tanous04ae99e2018-09-20 15:54:36 -07001373 }
Ed Tanousb9b2e0b2018-09-13 13:47:50 -07001374};
1375
1376class ManagerAccount : public Node
1377{
1378 public:
1379 ManagerAccount(CrowApp& app) :
1380 Node(app, "/redfish/v1/AccountService/Accounts/<str>/", std::string())
1381 {
Ed Tanousb9b2e0b2018-09-13 13:47:50 -07001382 entityPrivileges = {
1383 {boost::beast::http::verb::get,
1384 {{"ConfigureUsers"}, {"ConfigureManager"}, {"ConfigureSelf"}}},
1385 {boost::beast::http::verb::head, {{"Login"}}},
1386 {boost::beast::http::verb::patch, {{"ConfigureUsers"}}},
1387 {boost::beast::http::verb::put, {{"ConfigureUsers"}}},
1388 {boost::beast::http::verb::delete_, {{"ConfigureUsers"}}},
1389 {boost::beast::http::verb::post, {{"ConfigureUsers"}}}};
1390 }
1391
1392 private:
1393 void doGet(crow::Response& res, const crow::Request& req,
1394 const std::vector<std::string>& params) override
1395 {
Ed Tanous0f74e642018-11-12 15:17:05 -08001396 res.jsonValue = {
1397 {"@odata.context",
1398 "/redfish/v1/$metadata#ManagerAccount.ManagerAccount"},
1399 {"@odata.type", "#ManagerAccount.v1_0_3.ManagerAccount"},
Ed Tanous0f74e642018-11-12 15:17:05 -08001400 {"Name", "User Account"},
1401 {"Description", "User Account"},
1402 {"Password", nullptr},
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301403 {"RoleId", "Administrator"}};
Ed Tanous0f74e642018-11-12 15:17:05 -08001404
Ed Tanousb9b2e0b2018-09-13 13:47:50 -07001405 auto asyncResp = std::make_shared<AsyncResp>(res);
1406
1407 if (params.size() != 1)
1408 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001409 messages::internalError(asyncResp->res);
Ed Tanousb9b2e0b2018-09-13 13:47:50 -07001410 return;
1411 }
1412
1413 crow::connections::systemBus->async_method_call(
1414 [asyncResp, accountName{std::string(params[0])}](
1415 const boost::system::error_code ec,
1416 const ManagedObjectType& users) {
1417 if (ec)
1418 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001419 messages::internalError(asyncResp->res);
Ed Tanousb9b2e0b2018-09-13 13:47:50 -07001420 return;
1421 }
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301422 auto userIt = users.begin();
Ed Tanousb9b2e0b2018-09-13 13:47:50 -07001423
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301424 for (; userIt != users.end(); userIt++)
Ed Tanousb9b2e0b2018-09-13 13:47:50 -07001425 {
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301426 if (boost::ends_with(userIt->first.str, "/" + accountName))
Ed Tanousb9b2e0b2018-09-13 13:47:50 -07001427 {
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301428 break;
Ed Tanousb9b2e0b2018-09-13 13:47:50 -07001429 }
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301430 }
1431 if (userIt == users.end())
1432 {
1433 messages::resourceNotFound(asyncResp->res, "ManagerAccount",
1434 accountName);
1435 return;
1436 }
1437 for (const auto& interface : userIt->second)
1438 {
1439 if (interface.first ==
1440 "xyz.openbmc_project.User.Attributes")
Ed Tanousb9b2e0b2018-09-13 13:47:50 -07001441 {
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301442 for (const auto& property : interface.second)
Ed Tanous65b0dc32018-09-19 16:04:03 -07001443 {
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301444 if (property.first == "UserEnabled")
Ed Tanous65b0dc32018-09-19 16:04:03 -07001445 {
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301446 const bool* userEnabled =
Ed Tanousabf2add2019-01-22 16:40:12 -08001447 std::get_if<bool>(&property.second);
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301448 if (userEnabled == nullptr)
Ed Tanous65b0dc32018-09-19 16:04:03 -07001449 {
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301450 BMCWEB_LOG_ERROR
1451 << "UserEnabled wasn't a bool";
1452 messages::internalError(asyncResp->res);
1453 return;
Ed Tanous65b0dc32018-09-19 16:04:03 -07001454 }
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301455 asyncResp->res.jsonValue["Enabled"] =
1456 *userEnabled;
1457 }
1458 else if (property.first ==
1459 "UserLockedForFailedAttempt")
1460 {
1461 const bool* userLocked =
Ed Tanousabf2add2019-01-22 16:40:12 -08001462 std::get_if<bool>(&property.second);
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301463 if (userLocked == nullptr)
1464 {
1465 BMCWEB_LOG_ERROR << "UserLockedForF"
1466 "ailedAttempt "
1467 "wasn't a bool";
1468 messages::internalError(asyncResp->res);
1469 return;
1470 }
1471 asyncResp->res.jsonValue["Locked"] =
1472 *userLocked;
Ratan Gupta24c85422019-01-30 19:41:24 +05301473 asyncResp->res.jsonValue
1474 ["Locked@Redfish.AllowableValues"] = {
Gunnar Mills4d64ce32019-03-29 16:34:56 -05001475 "false"};
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301476 }
1477 else if (property.first == "UserPrivilege")
1478 {
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -06001479 const std::string* userPrivPtr =
Ed Tanousabf2add2019-01-22 16:40:12 -08001480 std::get_if<std::string>(&property.second);
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -06001481 if (userPrivPtr == nullptr)
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301482 {
1483 BMCWEB_LOG_ERROR
1484 << "UserPrivilege wasn't a "
1485 "string";
1486 messages::internalError(asyncResp->res);
1487 return;
1488 }
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -06001489 std::string role =
1490 getRoleIdFromPrivilege(*userPrivPtr);
1491 if (role.empty())
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301492 {
1493 BMCWEB_LOG_ERROR << "Invalid user role";
1494 messages::internalError(asyncResp->res);
1495 return;
1496 }
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -06001497 asyncResp->res.jsonValue["RoleId"] = role;
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301498
1499 asyncResp->res.jsonValue["Links"]["Role"] = {
1500 {"@odata.id", "/redfish/v1/AccountService/"
1501 "Roles/" +
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -06001502 role}};
Ed Tanous65b0dc32018-09-19 16:04:03 -07001503 }
1504 }
Ed Tanousb9b2e0b2018-09-13 13:47:50 -07001505 }
1506 }
1507
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301508 asyncResp->res.jsonValue["@odata.id"] =
1509 "/redfish/v1/AccountService/Accounts/" + accountName;
1510 asyncResp->res.jsonValue["Id"] = accountName;
1511 asyncResp->res.jsonValue["UserName"] = accountName;
Ed Tanousb9b2e0b2018-09-13 13:47:50 -07001512 },
1513 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
1514 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
1515 }
Ed Tanousa8408792018-09-05 16:08:38 -07001516
1517 void doPatch(crow::Response& res, const crow::Request& req,
1518 const std::vector<std::string>& params) override
1519 {
1520 auto asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanousa8408792018-09-05 16:08:38 -07001521 if (params.size() != 1)
1522 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001523 messages::internalError(asyncResp->res);
Ed Tanousa8408792018-09-05 16:08:38 -07001524 return;
1525 }
1526
Ed Tanousa24526d2018-12-10 15:17:59 -08001527 std::optional<std::string> newUserName;
1528 std::optional<std::string> password;
1529 std::optional<bool> enabled;
1530 std::optional<std::string> roleId;
Ratan Gupta24c85422019-01-30 19:41:24 +05301531 std::optional<bool> locked;
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301532 if (!json_util::readJson(req, res, "UserName", newUserName, "Password",
Ratan Gupta24c85422019-01-30 19:41:24 +05301533 password, "RoleId", roleId, "Enabled", enabled,
1534 "Locked", locked))
Ed Tanousa8408792018-09-05 16:08:38 -07001535 {
1536 return;
1537 }
1538
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301539 const std::string& username = params[0];
Ed Tanousa8408792018-09-05 16:08:38 -07001540
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301541 if (!newUserName)
1542 {
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -06001543 // If the username isn't being updated, we can update the
1544 // properties directly
Ratan Gupta24c85422019-01-30 19:41:24 +05301545 updateUserProperties(asyncResp, username, password, enabled, roleId,
1546 locked);
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301547 return;
1548 }
1549 else
1550 {
1551 crow::connections::systemBus->async_method_call(
1552 [this, asyncResp, username, password(std::move(password)),
1553 roleId(std::move(roleId)), enabled(std::move(enabled)),
Ratan Gupta24c85422019-01-30 19:41:24 +05301554 newUser{std::string(*newUserName)}, locked(std::move(locked))](
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301555 const boost::system::error_code ec) {
1556 if (ec)
Ed Tanousa8408792018-09-05 16:08:38 -07001557 {
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301558 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
1559 messages::resourceNotFound(
1560 asyncResp->res,
1561 "#ManagerAccount.v1_0_3.ManagerAccount", username);
1562 return;
1563 }
1564
1565 updateUserProperties(asyncResp, newUser, password, enabled,
Ratan Gupta24c85422019-01-30 19:41:24 +05301566 roleId, locked);
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301567 },
1568 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
1569 "xyz.openbmc_project.User.Manager", "RenameUser", username,
1570 *newUserName);
1571 }
1572 }
1573
1574 void updateUserProperties(std::shared_ptr<AsyncResp> asyncResp,
1575 const std::string& username,
Ed Tanousa24526d2018-12-10 15:17:59 -08001576 std::optional<std::string> password,
1577 std::optional<bool> enabled,
Ratan Gupta24c85422019-01-30 19:41:24 +05301578 std::optional<std::string> roleId,
1579 std::optional<bool> locked)
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301580 {
1581 if (password)
1582 {
1583 if (!pamUpdatePassword(username, *password))
1584 {
1585 BMCWEB_LOG_ERROR << "pamUpdatePassword Failed";
1586 messages::internalError(asyncResp->res);
1587 return;
1588 }
1589 }
1590
Ratan Gupta24c85422019-01-30 19:41:24 +05301591 std::string dbusObjectPath = "/xyz/openbmc_project/user/" + username;
1592 dbus::utility::escapePathForDbus(dbusObjectPath);
1593
Ratan Gupta22c33712019-05-03 21:50:28 +05301594 dbus::utility::checkDbusPathExists(
Ratan Gupta24c85422019-01-30 19:41:24 +05301595 dbusObjectPath,
1596 [dbusObjectPath(std::move(dbusObjectPath)), username,
1597 password(std::move(password)), roleId(std::move(roleId)),
1598 enabled(std::move(enabled)), locked(std::move(locked)),
1599 asyncResp{std::move(asyncResp)}](int rc) {
1600 if (!rc)
1601 {
1602 messages::invalidObject(asyncResp->res, username.c_str());
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301603 return;
Ratan Gupta24c85422019-01-30 19:41:24 +05301604 }
1605 if (enabled)
1606 {
1607 crow::connections::systemBus->async_method_call(
1608 [asyncResp](const boost::system::error_code ec) {
1609 if (ec)
1610 {
1611 BMCWEB_LOG_ERROR << "D-Bus responses error: "
1612 << ec;
1613 messages::internalError(asyncResp->res);
1614 return;
1615 }
1616 messages::success(asyncResp->res);
1617 return;
1618 },
1619 "xyz.openbmc_project.User.Manager",
1620 dbusObjectPath.c_str(),
1621 "org.freedesktop.DBus.Properties", "Set",
1622 "xyz.openbmc_project.User.Attributes", "UserEnabled",
1623 std::variant<bool>{*enabled});
1624 }
Ed Tanous9712f8a2018-09-21 13:38:49 -07001625
Ratan Gupta24c85422019-01-30 19:41:24 +05301626 if (roleId)
1627 {
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -06001628 std::string priv = getPrivilegeFromRoleId(*roleId);
Ratan Gupta24c85422019-01-30 19:41:24 +05301629 if (priv.empty())
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301630 {
Ratan Gupta24c85422019-01-30 19:41:24 +05301631 messages::propertyValueNotInList(asyncResp->res,
1632 *roleId, "RoleId");
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301633 return;
1634 }
Ratan Gupta24c85422019-01-30 19:41:24 +05301635
1636 crow::connections::systemBus->async_method_call(
1637 [asyncResp](const boost::system::error_code ec) {
1638 if (ec)
1639 {
1640 BMCWEB_LOG_ERROR << "D-Bus responses error: "
1641 << ec;
1642 messages::internalError(asyncResp->res);
1643 return;
1644 }
1645 messages::success(asyncResp->res);
1646 },
1647 "xyz.openbmc_project.User.Manager",
1648 dbusObjectPath.c_str(),
1649 "org.freedesktop.DBus.Properties", "Set",
1650 "xyz.openbmc_project.User.Attributes", "UserPrivilege",
1651 std::variant<std::string>{priv});
1652 }
1653
1654 if (locked)
1655 {
1656 // admin can unlock the account which is locked by
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -06001657 // successive authentication failures but admin should
1658 // not be allowed to lock an account.
Ratan Gupta24c85422019-01-30 19:41:24 +05301659 if (*locked)
1660 {
1661 messages::propertyValueNotInList(asyncResp->res, "true",
1662 "Locked");
1663 return;
1664 }
1665
1666 crow::connections::systemBus->async_method_call(
1667 [asyncResp](const boost::system::error_code ec) {
1668 if (ec)
1669 {
1670 BMCWEB_LOG_ERROR << "D-Bus responses error: "
1671 << ec;
1672 messages::internalError(asyncResp->res);
1673 return;
1674 }
1675 messages::success(asyncResp->res);
1676 return;
1677 },
1678 "xyz.openbmc_project.User.Manager",
1679 dbusObjectPath.c_str(),
1680 "org.freedesktop.DBus.Properties", "Set",
1681 "xyz.openbmc_project.User.Attributes",
1682 "UserLockedForFailedAttempt",
1683 sdbusplus::message::variant<bool>{*locked});
1684 }
1685 });
Ed Tanousa8408792018-09-05 16:08:38 -07001686 }
Ed Tanous06e086d2018-09-19 17:19:52 -07001687
1688 void doDelete(crow::Response& res, const crow::Request& req,
1689 const std::vector<std::string>& params) override
1690 {
1691 auto asyncResp = std::make_shared<AsyncResp>(res);
1692
1693 if (params.size() != 1)
1694 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001695 messages::internalError(asyncResp->res);
Ed Tanous06e086d2018-09-19 17:19:52 -07001696 return;
1697 }
1698
1699 const std::string userPath = "/xyz/openbmc_project/user/" + params[0];
1700
1701 crow::connections::systemBus->async_method_call(
1702 [asyncResp, username{std::move(params[0])}](
1703 const boost::system::error_code ec) {
1704 if (ec)
1705 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001706 messages::resourceNotFound(
1707 asyncResp->res, "#ManagerAccount.v1_0_3.ManagerAccount",
1708 username);
Ed Tanous06e086d2018-09-19 17:19:52 -07001709 return;
1710 }
1711
Jason M. Billsf12894f2018-10-09 12:45:45 -07001712 messages::accountRemoved(asyncResp->res);
Ed Tanous06e086d2018-09-19 17:19:52 -07001713 },
1714 "xyz.openbmc_project.User.Manager", userPath,
1715 "xyz.openbmc_project.Object.Delete", "Delete");
1716 }
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301717};
Lewanczyk, Dawid88d16c92018-02-02 14:51:09 +01001718
Ed Tanous1abe55e2018-09-05 08:30:59 -07001719} // namespace redfish