blob: 59e2d1cd677336bf159cc6f6c9615473f3d97be3 [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 {
AppaRao Pulic80fee52019-10-16 14:49:36 +053087 return "ReadOnly";
AppaRao Puli84e12cb2018-10-11 01:28:15 +053088 }
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 }
AppaRao Pulic80fee52019-10-16 14:49:36 +0530105 else if (role == "ReadOnly")
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530106 {
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
jayaprakash Mutyala66b5ca72019-08-07 20:26:37 +0000116void userErrorMessageHandler(const sd_bus_error* e,
117 std::shared_ptr<AsyncResp> asyncResp,
118 const std::string& newUser,
119 const std::string& username)
120{
121 const char* errorMessage = e->name;
122 if (e == nullptr)
123 {
124 messages::internalError(asyncResp->res);
125 return;
126 }
127
128 if (strcmp(errorMessage,
129 "xyz.openbmc_project.User.Common.Error.UserNameExists") == 0)
130 {
131 messages::resourceAlreadyExists(asyncResp->res,
132 "#ManagerAccount.v1_0_3.ManagerAccount",
133 "UserName", newUser);
134 }
135 else if (strcmp(errorMessage, "xyz.openbmc_project.User.Common.Error."
136 "UserNameDoesNotExist") == 0)
137 {
138 messages::resourceNotFound(
139 asyncResp->res, "#ManagerAccount.v1_0_3.ManagerAccount", username);
140 }
141 else if (strcmp(errorMessage,
142 "xyz.openbmc_project.Common.Error.InvalidArgument") == 0)
143 {
144 messages::propertyValueFormatError(asyncResp->res, newUser, "UserName");
145 }
146 else if (strcmp(errorMessage,
147 "xyz.openbmc_project.User.Common.Error.NoResource") == 0)
148 {
149 messages::createLimitReachedForResource(asyncResp->res);
150 }
151 else if (strcmp(errorMessage, "xyz.openbmc_project.User.Common.Error."
152 "UserNameGroupFail") == 0)
153 {
154 messages::propertyValueFormatError(asyncResp->res, newUser, "UserName");
155 }
156 else
157 {
158 messages::internalError(asyncResp->res);
159 }
160
161 return;
162}
163
Ratan Gupta6973a582018-12-13 18:25:44 +0530164void parseLDAPConfigData(nlohmann::json& json_response,
Ratan Guptaab828d72019-04-22 14:18:33 +0530165 const LDAPConfigData& confData,
166 const std::string& ldapType)
Ratan Gupta6973a582018-12-13 18:25:44 +0530167{
Ratan Guptaab828d72019-04-22 14:18:33 +0530168 std::string service =
169 (ldapType == "LDAP") ? "LDAPService" : "ActiveDirectoryService";
Marri Devender Rao37cce912019-02-20 01:05:22 -0600170 nlohmann::json ldap = {
Ratan Gupta6973a582018-12-13 18:25:44 +0530171 {"AccountProviderType", service},
Ratan Gupta6973a582018-12-13 18:25:44 +0530172 {"ServiceEnabled", confData.serviceEnabled},
173 {"ServiceAddresses", nlohmann::json::array({confData.uri})},
174 {"Authentication",
175 {{"AuthenticationType", "UsernameAndPassword"},
Ratan Gupta6973a582018-12-13 18:25:44 +0530176 {"Username", confData.bindDN},
177 {"Password", nullptr}}},
178 {"LDAPService",
179 {{"SearchSettings",
180 {{"BaseDistinguishedNames",
181 nlohmann::json::array({confData.baseDN})},
182 {"UsernameAttribute", confData.userNameAttribute},
183 {"GroupsAttribute", confData.groupAttribute}}}}},
184 };
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600185
Marri Devender Rao37cce912019-02-20 01:05:22 -0600186 json_response[ldapType].update(std::move(ldap));
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600187
188 nlohmann::json& roleMapArray = json_response[ldapType]["RemoteRoleMapping"];
189 roleMapArray = nlohmann::json::array();
190 for (auto& obj : confData.groupRoleList)
191 {
192 BMCWEB_LOG_DEBUG << "Pushing the data groupName="
193 << obj.second.groupName << "\n";
194 roleMapArray.push_back(
195 {nlohmann::json::array({"RemoteGroup", obj.second.groupName}),
196 nlohmann::json::array(
197 {"LocalRole", getRoleIdFromPrivilege(obj.second.privilege)})});
198 }
Ratan Gupta6973a582018-12-13 18:25:44 +0530199}
200
201/**
Ratan Gupta06785242019-07-26 22:30:16 +0530202 * @brief validates given JSON input and then calls appropriate method to
203 * create, to delete or to set Rolemapping object based on the given input.
204 *
205 */
206static void handleRoleMapPatch(
207 const std::shared_ptr<AsyncResp>& asyncResp,
208 const std::vector<std::pair<std::string, LDAPRoleMapData>>& roleMapObjData,
209 const std::string& serverType, std::vector<nlohmann::json>& input)
210{
211 for (size_t index = 0; index < input.size(); index++)
212 {
213 nlohmann::json& thisJson = input[index];
214
215 if (thisJson.is_null())
216 {
217 // delete the existing object
218 if (index < roleMapObjData.size())
219 {
220 crow::connections::systemBus->async_method_call(
221 [asyncResp, roleMapObjData, serverType,
222 index](const boost::system::error_code ec) {
223 if (ec)
224 {
225 BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
226 messages::internalError(asyncResp->res);
227 return;
228 }
229 asyncResp->res
230 .jsonValue[serverType]["RemoteRoleMapping"][index] =
231 nullptr;
232 },
233 ldapDbusService, roleMapObjData[index].first,
234 "xyz.openbmc_project.Object.Delete", "Delete");
235 }
236 else
237 {
238 BMCWEB_LOG_ERROR << "Can't delete the object";
239 messages::propertyValueTypeError(
240 asyncResp->res, thisJson.dump(),
241 "RemoteRoleMapping/" + std::to_string(index));
242 return;
243 }
244 }
245 else if (thisJson.empty())
246 {
247 // Don't do anything for the empty objects,parse next json
248 // eg {"RemoteRoleMapping",[{}]}
249 }
250 else
251 {
252 // update/create the object
253 std::optional<std::string> remoteGroup;
254 std::optional<std::string> localRole;
255
256 if (!json_util::readJson(thisJson, asyncResp->res, "RemoteGroup",
257 remoteGroup, "LocalRole", localRole))
258 {
259 continue;
260 }
261
262 // Update existing RoleMapping Object
263 if (index < roleMapObjData.size())
264 {
265 BMCWEB_LOG_DEBUG << "Update Role Map Object";
266 // If "RemoteGroup" info is provided
267 if (remoteGroup)
268 {
269 crow::connections::systemBus->async_method_call(
270 [asyncResp, roleMapObjData, serverType, index,
271 remoteGroup](const boost::system::error_code ec) {
272 if (ec)
273 {
274 BMCWEB_LOG_ERROR << "DBUS response error: "
275 << ec;
276 messages::internalError(asyncResp->res);
277 return;
278 }
279 asyncResp->res
280 .jsonValue[serverType]["RemoteRoleMapping"]
281 [index]["RemoteGroup"] = *remoteGroup;
282 },
283 ldapDbusService, roleMapObjData[index].first,
284 propertyInterface, "Set",
285 "xyz.openbmc_project.User.PrivilegeMapperEntry",
286 "GroupName",
287 std::variant<std::string>(std::move(*remoteGroup)));
288 }
289
290 // If "LocalRole" info is provided
291 if (localRole)
292 {
293 crow::connections::systemBus->async_method_call(
294 [asyncResp, roleMapObjData, serverType, index,
295 localRole](const boost::system::error_code ec) {
296 if (ec)
297 {
298 BMCWEB_LOG_ERROR << "DBUS response error: "
299 << ec;
300 messages::internalError(asyncResp->res);
301 return;
302 }
303 asyncResp->res
304 .jsonValue[serverType]["RemoteRoleMapping"]
305 [index]["LocalRole"] = *localRole;
306 },
307 ldapDbusService, roleMapObjData[index].first,
308 propertyInterface, "Set",
309 "xyz.openbmc_project.User.PrivilegeMapperEntry",
310 "Privilege",
311 std::variant<std::string>(
312 getPrivilegeFromRoleId(std::move(*localRole))));
313 }
314 }
315 // Create a new RoleMapping Object.
316 else
317 {
318 BMCWEB_LOG_DEBUG
319 << "setRoleMappingProperties: Creating new Object";
320 std::string pathString =
321 "RemoteRoleMapping/" + std::to_string(index);
322
323 if (!localRole)
324 {
325 messages::propertyMissing(asyncResp->res,
326 pathString + "/LocalRole");
327 continue;
328 }
329 if (!remoteGroup)
330 {
331 messages::propertyMissing(asyncResp->res,
332 pathString + "/RemoteGroup");
333 continue;
334 }
335
336 std::string dbusObjectPath;
337 if (serverType == "ActiveDirectory")
338 {
339 dbusObjectPath = ADConfigObject;
340 }
341 else if (serverType == "LDAP")
342 {
343 dbusObjectPath = ldapConfigObject;
344 }
345
346 BMCWEB_LOG_DEBUG << "Remote Group=" << *remoteGroup
347 << ",LocalRole=" << *localRole;
348
349 crow::connections::systemBus->async_method_call(
Ed Tanous271584a2019-07-09 16:24:22 -0700350 [asyncResp, serverType, localRole,
Ratan Gupta06785242019-07-26 22:30:16 +0530351 remoteGroup](const boost::system::error_code ec) {
352 if (ec)
353 {
354 BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
355 messages::internalError(asyncResp->res);
356 return;
357 }
358 nlohmann::json& remoteRoleJson =
359 asyncResp->res
360 .jsonValue[serverType]["RemoteRoleMapping"];
361 remoteRoleJson.push_back(
362 {{"LocalRole", *localRole},
363 {"RemoteGroup", *remoteGroup}});
364 },
365 ldapDbusService, dbusObjectPath, ldapPrivMapperInterface,
366 "Create", std::move(*remoteGroup),
367 getPrivilegeFromRoleId(std::move(*localRole)));
368 }
369 }
370 }
371}
372
373/**
Ratan Gupta6973a582018-12-13 18:25:44 +0530374 * Function that retrieves all properties for LDAP config object
375 * into JSON
376 */
377template <typename CallbackFunc>
378inline void getLDAPConfigData(const std::string& ldapType,
379 CallbackFunc&& callback)
380{
Ratan Guptaab828d72019-04-22 14:18:33 +0530381
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600382 const std::array<const char*, 2> interfaces = {ldapEnableInterface,
Ratan Gupta6973a582018-12-13 18:25:44 +0530383 ldapConfigInterface};
384
385 crow::connections::systemBus->async_method_call(
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600386 [callback, ldapType](const boost::system::error_code ec,
387 const GetObjectType& resp) {
388 LDAPConfigData confData{};
389 if (ec || resp.empty())
390 {
391 BMCWEB_LOG_ERROR << "DBUS response error during getting of "
392 "service name: "
393 << ec;
394 callback(false, confData, ldapType);
395 return;
396 }
397 std::string service = resp.begin()->first;
398 crow::connections::systemBus->async_method_call(
399 [callback, ldapType](const boost::system::error_code error_code,
400 const ManagedObjectType& ldapObjects) {
401 LDAPConfigData confData{};
402 if (error_code)
403 {
404 callback(false, confData, ldapType);
405 BMCWEB_LOG_ERROR << "D-Bus responses error: "
406 << error_code;
407 return;
408 }
409
410 std::string ldapDbusType;
411 std::string searchString;
412
413 if (ldapType == "LDAP")
414 {
415 ldapDbusType = "xyz.openbmc_project.User.Ldap.Config."
416 "Type.OpenLdap";
417 searchString = "openldap";
418 }
419 else if (ldapType == "ActiveDirectory")
420 {
421 ldapDbusType =
422 "xyz.openbmc_project.User.Ldap.Config.Type."
423 "ActiveDirectory";
424 searchString = "active_directory";
425 }
426 else
427 {
428 BMCWEB_LOG_ERROR
429 << "Can't get the DbusType for the given type="
430 << ldapType;
431 callback(false, confData, ldapType);
432 return;
433 }
434
435 std::string ldapEnableInterfaceStr = ldapEnableInterface;
436 std::string ldapConfigInterfaceStr = ldapConfigInterface;
437
438 for (const auto& object : ldapObjects)
439 {
440 // let's find the object whose ldap type is equal to the
441 // given type
442 if (object.first.str.find(searchString) ==
443 std::string::npos)
444 {
445 continue;
446 }
447
448 for (const auto& interface : object.second)
449 {
450 if (interface.first == ldapEnableInterfaceStr)
451 {
452 // rest of the properties are string.
453 for (const auto& property : interface.second)
454 {
455 if (property.first == "Enabled")
456 {
457 const bool* value =
458 std::get_if<bool>(&property.second);
459 if (value == nullptr)
460 {
461 continue;
462 }
463 confData.serviceEnabled = *value;
464 break;
465 }
466 }
467 }
468 else if (interface.first == ldapConfigInterfaceStr)
469 {
470
471 for (const auto& property : interface.second)
472 {
Ed Tanous271584a2019-07-09 16:24:22 -0700473 const std::string* strValue =
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600474 std::get_if<std::string>(
475 &property.second);
Ed Tanous271584a2019-07-09 16:24:22 -0700476 if (strValue == nullptr)
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600477 {
478 continue;
479 }
480 if (property.first == "LDAPServerURI")
481 {
Ed Tanous271584a2019-07-09 16:24:22 -0700482 confData.uri = *strValue;
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600483 }
484 else if (property.first == "LDAPBindDN")
485 {
Ed Tanous271584a2019-07-09 16:24:22 -0700486 confData.bindDN = *strValue;
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600487 }
488 else if (property.first == "LDAPBaseDN")
489 {
Ed Tanous271584a2019-07-09 16:24:22 -0700490 confData.baseDN = *strValue;
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600491 }
492 else if (property.first ==
493 "LDAPSearchScope")
494 {
Ed Tanous271584a2019-07-09 16:24:22 -0700495 confData.searchScope = *strValue;
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600496 }
497 else if (property.first ==
498 "GroupNameAttribute")
499 {
Ed Tanous271584a2019-07-09 16:24:22 -0700500 confData.groupAttribute = *strValue;
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600501 }
502 else if (property.first ==
503 "UserNameAttribute")
504 {
Ed Tanous271584a2019-07-09 16:24:22 -0700505 confData.userNameAttribute = *strValue;
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600506 }
507 else if (property.first == "LDAPType")
508 {
Ed Tanous271584a2019-07-09 16:24:22 -0700509 confData.serverType = *strValue;
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600510 }
511 }
512 }
513 else if (interface.first ==
514 "xyz.openbmc_project.User."
515 "PrivilegeMapperEntry")
516 {
517 LDAPRoleMapData roleMapData{};
518 for (const auto& property : interface.second)
519 {
Ed Tanous271584a2019-07-09 16:24:22 -0700520 const std::string* strValue =
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600521 std::get_if<std::string>(
522 &property.second);
523
Ed Tanous271584a2019-07-09 16:24:22 -0700524 if (strValue == nullptr)
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600525 {
526 continue;
527 }
528
529 if (property.first == "GroupName")
530 {
Ed Tanous271584a2019-07-09 16:24:22 -0700531 roleMapData.groupName = *strValue;
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600532 }
533 else if (property.first == "Privilege")
534 {
Ed Tanous271584a2019-07-09 16:24:22 -0700535 roleMapData.privilege = *strValue;
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600536 }
537 }
538
Ed Tanous0f0353b2019-10-24 11:37:51 -0700539 confData.groupRoleList.emplace_back(
540 object.first.str, roleMapData);
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600541 }
542 }
543 }
544 callback(true, confData, ldapType);
545 },
546 service, ldapRootObject, dbusObjManagerIntf,
547 "GetManagedObjects");
548 },
549 mapperBusName, mapperObjectPath, mapperIntf, "GetObject",
550 ldapConfigObject, interfaces);
Ratan Gupta6973a582018-12-13 18:25:44 +0530551}
552
Ed Tanous1abe55e2018-09-05 08:30:59 -0700553class AccountService : public Node
554{
555 public:
James Feisteecd51a2019-11-04 21:19:48 +0000556 AccountService(CrowApp& app) : Node(app, "/redfish/v1/AccountService/")
Ed Tanous1abe55e2018-09-05 08:30:59 -0700557 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700558 entityPrivileges = {
559 {boost::beast::http::verb::get,
560 {{"ConfigureUsers"}, {"ConfigureManager"}}},
561 {boost::beast::http::verb::head, {{"Login"}}},
562 {boost::beast::http::verb::patch, {{"ConfigureUsers"}}},
563 {boost::beast::http::verb::put, {{"ConfigureUsers"}}},
564 {boost::beast::http::verb::delete_, {{"ConfigureUsers"}}},
565 {boost::beast::http::verb::post, {{"ConfigureUsers"}}}};
566 }
Lewanczyk, Dawid88d16c92018-02-02 14:51:09 +0100567
Ed Tanous1abe55e2018-09-05 08:30:59 -0700568 private:
Ratan Gupta8a07d282019-03-16 08:33:47 +0530569 /**
570 * @brief parses the authentication section under the LDAP
571 * @param input JSON data
572 * @param asyncResp pointer to the JSON response
573 * @param userName userName to be filled from the given JSON.
574 * @param password password to be filled from the given JSON.
575 */
576 void
577 parseLDAPAuthenticationJson(nlohmann::json input,
578 const std::shared_ptr<AsyncResp>& asyncResp,
579 std::optional<std::string>& username,
580 std::optional<std::string>& password)
581 {
582 std::optional<std::string> authType;
583
584 if (!json_util::readJson(input, asyncResp->res, "AuthenticationType",
585 authType, "Username", username, "Password",
586 password))
587 {
588 return;
589 }
590 if (!authType)
591 {
592 return;
593 }
594 if (*authType != "UsernameAndPassword")
595 {
596 messages::propertyValueNotInList(asyncResp->res, *authType,
597 "AuthenticationType");
598 return;
599 }
600 }
601 /**
602 * @brief parses the LDAPService section under the LDAP
603 * @param input JSON data
604 * @param asyncResp pointer to the JSON response
605 * @param baseDNList baseDN to be filled from the given JSON.
606 * @param userNameAttribute userName to be filled from the given JSON.
607 * @param groupaAttribute password to be filled from the given JSON.
608 */
609
610 void parseLDAPServiceJson(
611 nlohmann::json input, const std::shared_ptr<AsyncResp>& asyncResp,
612 std::optional<std::vector<std::string>>& baseDNList,
613 std::optional<std::string>& userNameAttribute,
614 std::optional<std::string>& groupsAttribute)
615 {
616 std::optional<nlohmann::json> searchSettings;
617
618 if (!json_util::readJson(input, asyncResp->res, "SearchSettings",
619 searchSettings))
620 {
621 return;
622 }
623 if (!searchSettings)
624 {
625 return;
626 }
627 if (!json_util::readJson(*searchSettings, asyncResp->res,
628 "BaseDistinguishedNames", baseDNList,
629 "UsernameAttribute", userNameAttribute,
630 "GroupsAttribute", groupsAttribute))
631 {
632 return;
633 }
634 }
635 /**
636 * @brief updates the LDAP server address and updates the
637 json response with the new value.
638 * @param serviceAddressList address to be updated.
639 * @param asyncResp pointer to the JSON response
640 * @param ldapServerElementName Type of LDAP
641 server(openLDAP/ActiveDirectory)
642 */
643
644 void handleServiceAddressPatch(
645 const std::vector<std::string>& serviceAddressList,
646 const std::shared_ptr<AsyncResp>& asyncResp,
647 const std::string& ldapServerElementName,
648 const std::string& ldapConfigObject)
649 {
650 crow::connections::systemBus->async_method_call(
651 [asyncResp, ldapServerElementName,
652 serviceAddressList](const boost::system::error_code ec) {
653 if (ec)
654 {
655 BMCWEB_LOG_DEBUG
656 << "Error Occured in updating the service address";
657 messages::internalError(asyncResp->res);
658 return;
659 }
660 std::vector<std::string> modifiedserviceAddressList = {
661 serviceAddressList.front()};
662 asyncResp->res
663 .jsonValue[ldapServerElementName]["ServiceAddresses"] =
664 modifiedserviceAddressList;
665 if ((serviceAddressList).size() > 1)
666 {
667 messages::propertyValueModified(asyncResp->res,
668 "ServiceAddresses",
669 serviceAddressList.front());
670 }
671 BMCWEB_LOG_DEBUG << "Updated the service address";
672 },
673 ldapDbusService, ldapConfigObject, propertyInterface, "Set",
674 ldapConfigInterface, "LDAPServerURI",
675 std::variant<std::string>(serviceAddressList.front()));
676 }
677 /**
678 * @brief updates the LDAP Bind DN and updates the
679 json response with the new value.
680 * @param username name of the user which needs to be updated.
681 * @param asyncResp pointer to the JSON response
682 * @param ldapServerElementName Type of LDAP
683 server(openLDAP/ActiveDirectory)
684 */
685
686 void handleUserNamePatch(const std::string& username,
687 const std::shared_ptr<AsyncResp>& asyncResp,
688 const std::string& ldapServerElementName,
689 const std::string& ldapConfigObject)
690 {
691 crow::connections::systemBus->async_method_call(
692 [asyncResp, username,
693 ldapServerElementName](const boost::system::error_code ec) {
694 if (ec)
695 {
696 BMCWEB_LOG_DEBUG
697 << "Error occured in updating the username";
698 messages::internalError(asyncResp->res);
699 return;
700 }
701 asyncResp->res.jsonValue[ldapServerElementName]
702 ["Authentication"]["Username"] =
703 username;
704 BMCWEB_LOG_DEBUG << "Updated the username";
705 },
706 ldapDbusService, ldapConfigObject, propertyInterface, "Set",
707 ldapConfigInterface, "LDAPBindDN",
708 std::variant<std::string>(username));
709 }
710
711 /**
712 * @brief updates the LDAP password
713 * @param password : ldap password which needs to be updated.
714 * @param asyncResp pointer to the JSON response
715 * @param ldapServerElementName Type of LDAP
716 * server(openLDAP/ActiveDirectory)
717 */
718
719 void handlePasswordPatch(const std::string& password,
720 const std::shared_ptr<AsyncResp>& asyncResp,
721 const std::string& ldapServerElementName,
722 const std::string& ldapConfigObject)
723 {
724 crow::connections::systemBus->async_method_call(
725 [asyncResp, password,
726 ldapServerElementName](const boost::system::error_code ec) {
727 if (ec)
728 {
729 BMCWEB_LOG_DEBUG
730 << "Error occured in updating the password";
731 messages::internalError(asyncResp->res);
732 return;
733 }
734 asyncResp->res.jsonValue[ldapServerElementName]
735 ["Authentication"]["Password"] = "";
736 BMCWEB_LOG_DEBUG << "Updated the password";
737 },
738 ldapDbusService, ldapConfigObject, propertyInterface, "Set",
739 ldapConfigInterface, "LDAPBindDNPassword",
740 std::variant<std::string>(password));
741 }
742
743 /**
744 * @brief updates the LDAP BaseDN and updates the
745 json response with the new value.
746 * @param baseDNList baseDN list which needs to be updated.
747 * @param asyncResp pointer to the JSON response
748 * @param ldapServerElementName Type of LDAP
749 server(openLDAP/ActiveDirectory)
750 */
751
752 void handleBaseDNPatch(const std::vector<std::string>& baseDNList,
753 const std::shared_ptr<AsyncResp>& asyncResp,
754 const std::string& ldapServerElementName,
755 const std::string& ldapConfigObject)
756 {
757 crow::connections::systemBus->async_method_call(
758 [asyncResp, baseDNList,
759 ldapServerElementName](const boost::system::error_code ec) {
760 if (ec)
761 {
762 BMCWEB_LOG_DEBUG << "Error Occured in Updating the base DN";
763 messages::internalError(asyncResp->res);
764 return;
765 }
766 auto& serverTypeJson =
767 asyncResp->res.jsonValue[ldapServerElementName];
768 auto& searchSettingsJson =
769 serverTypeJson["LDAPService"]["SearchSettings"];
770 std::vector<std::string> modifiedBaseDNList = {
771 baseDNList.front()};
772 searchSettingsJson["BaseDistinguishedNames"] =
773 modifiedBaseDNList;
774 if (baseDNList.size() > 1)
775 {
776 messages::propertyValueModified(asyncResp->res,
777 "BaseDistinguishedNames",
778 baseDNList.front());
779 }
780 BMCWEB_LOG_DEBUG << "Updated the base DN";
781 },
782 ldapDbusService, ldapConfigObject, propertyInterface, "Set",
783 ldapConfigInterface, "LDAPBaseDN",
784 std::variant<std::string>(baseDNList.front()));
785 }
786 /**
787 * @brief updates the LDAP user name attribute and updates the
788 json response with the new value.
789 * @param userNameAttribute attribute to be updated.
790 * @param asyncResp pointer to the JSON response
791 * @param ldapServerElementName Type of LDAP
792 server(openLDAP/ActiveDirectory)
793 */
794
795 void handleUserNameAttrPatch(const std::string& userNameAttribute,
796 const std::shared_ptr<AsyncResp>& asyncResp,
797 const std::string& ldapServerElementName,
798 const std::string& ldapConfigObject)
799 {
800 crow::connections::systemBus->async_method_call(
801 [asyncResp, userNameAttribute,
802 ldapServerElementName](const boost::system::error_code ec) {
803 if (ec)
804 {
805 BMCWEB_LOG_DEBUG << "Error Occured in Updating the "
806 "username attribute";
807 messages::internalError(asyncResp->res);
808 return;
809 }
810 auto& serverTypeJson =
811 asyncResp->res.jsonValue[ldapServerElementName];
812 auto& searchSettingsJson =
813 serverTypeJson["LDAPService"]["SearchSettings"];
814 searchSettingsJson["UsernameAttribute"] = userNameAttribute;
815 BMCWEB_LOG_DEBUG << "Updated the user name attr.";
816 },
817 ldapDbusService, ldapConfigObject, propertyInterface, "Set",
818 ldapConfigInterface, "UserNameAttribute",
819 std::variant<std::string>(userNameAttribute));
820 }
821 /**
822 * @brief updates the LDAP group attribute and updates the
823 json response with the new value.
824 * @param groupsAttribute attribute to be updated.
825 * @param asyncResp pointer to the JSON response
826 * @param ldapServerElementName Type of LDAP
827 server(openLDAP/ActiveDirectory)
828 */
829
830 void handleGroupNameAttrPatch(const std::string& groupsAttribute,
831 const std::shared_ptr<AsyncResp>& asyncResp,
832 const std::string& ldapServerElementName,
833 const std::string& ldapConfigObject)
834 {
835 crow::connections::systemBus->async_method_call(
836 [asyncResp, groupsAttribute,
837 ldapServerElementName](const boost::system::error_code ec) {
838 if (ec)
839 {
840 BMCWEB_LOG_DEBUG << "Error Occured in Updating the "
841 "groupname attribute";
842 messages::internalError(asyncResp->res);
843 return;
844 }
845 auto& serverTypeJson =
846 asyncResp->res.jsonValue[ldapServerElementName];
847 auto& searchSettingsJson =
848 serverTypeJson["LDAPService"]["SearchSettings"];
849 searchSettingsJson["GroupsAttribute"] = groupsAttribute;
850 BMCWEB_LOG_DEBUG << "Updated the groupname attr";
851 },
852 ldapDbusService, ldapConfigObject, propertyInterface, "Set",
853 ldapConfigInterface, "GroupNameAttribute",
854 std::variant<std::string>(groupsAttribute));
855 }
856 /**
857 * @brief updates the LDAP service enable and updates the
858 json response with the new value.
859 * @param input JSON data.
860 * @param asyncResp pointer to the JSON response
861 * @param ldapServerElementName Type of LDAP
862 server(openLDAP/ActiveDirectory)
863 */
864
865 void handleServiceEnablePatch(bool serviceEnabled,
866 const std::shared_ptr<AsyncResp>& asyncResp,
867 const std::string& ldapServerElementName,
868 const std::string& ldapConfigObject)
869 {
870 crow::connections::systemBus->async_method_call(
871 [asyncResp, serviceEnabled,
872 ldapServerElementName](const boost::system::error_code ec) {
873 if (ec)
874 {
875 BMCWEB_LOG_DEBUG
876 << "Error Occured in Updating the service enable";
877 messages::internalError(asyncResp->res);
878 return;
879 }
880 asyncResp->res
881 .jsonValue[ldapServerElementName]["ServiceEnabled"] =
882 serviceEnabled;
883 BMCWEB_LOG_DEBUG << "Updated Service enable = "
884 << serviceEnabled;
885 },
886 ldapDbusService, ldapConfigObject, propertyInterface, "Set",
887 ldapEnableInterface, "Enabled", std::variant<bool>(serviceEnabled));
888 }
889
890 /**
891 * @brief Get the required values from the given JSON, validates the
892 * value and create the LDAP config object.
893 * @param input JSON data
894 * @param asyncResp pointer to the JSON response
895 * @param serverType Type of LDAP server(openLDAP/ActiveDirectory)
896 */
897
898 void handleLDAPPatch(nlohmann::json& input,
899 const std::shared_ptr<AsyncResp>& asyncResp,
900 const crow::Request& req,
901 const std::vector<std::string>& params,
902 const std::string& serverType)
903 {
Ratan Guptaeb2bbe52019-04-22 14:27:01 +0530904 std::string dbusObjectPath;
905 if (serverType == "ActiveDirectory")
906 {
907 dbusObjectPath = ADConfigObject;
908 }
909 else if (serverType == "LDAP")
910 {
911 dbusObjectPath = ldapConfigObject;
912 }
913
Ratan Gupta8a07d282019-03-16 08:33:47 +0530914 std::optional<nlohmann::json> authentication;
915 std::optional<nlohmann::json> ldapService;
916 std::optional<std::string> accountProviderType;
917 std::optional<std::vector<std::string>> serviceAddressList;
918 std::optional<bool> serviceEnabled;
919 std::optional<std::vector<std::string>> baseDNList;
920 std::optional<std::string> userNameAttribute;
921 std::optional<std::string> groupsAttribute;
922 std::optional<std::string> userName;
923 std::optional<std::string> password;
Ratan Gupta06785242019-07-26 22:30:16 +0530924 std::optional<std::vector<nlohmann::json>> remoteRoleMapData;
Ratan Gupta8a07d282019-03-16 08:33:47 +0530925
926 if (!json_util::readJson(input, asyncResp->res, "Authentication",
927 authentication, "LDAPService", ldapService,
928 "ServiceAddresses", serviceAddressList,
929 "AccountProviderType", accountProviderType,
Ratan Gupta06785242019-07-26 22:30:16 +0530930 "ServiceEnabled", serviceEnabled,
931 "RemoteRoleMapping", remoteRoleMapData))
Ratan Gupta8a07d282019-03-16 08:33:47 +0530932 {
933 return;
934 }
935
936 if (authentication)
937 {
938 parseLDAPAuthenticationJson(*authentication, asyncResp, userName,
939 password);
940 }
941 if (ldapService)
942 {
943 parseLDAPServiceJson(*ldapService, asyncResp, baseDNList,
944 userNameAttribute, groupsAttribute);
945 }
946 if (accountProviderType)
947 {
948 messages::propertyNotWritable(asyncResp->res,
949 "AccountProviderType");
950 }
951 if (serviceAddressList)
952 {
953 if ((*serviceAddressList).size() == 0)
954 {
955 messages::propertyValueNotInList(asyncResp->res, "[]",
956 "ServiceAddress");
957 return;
958 }
959 }
960 if (baseDNList)
961 {
962 if ((*baseDNList).size() == 0)
963 {
964 messages::propertyValueNotInList(asyncResp->res, "[]",
965 "BaseDistinguishedNames");
966 return;
967 }
968 }
969
970 // nothing to update, then return
971 if (!userName && !password && !serviceAddressList && !baseDNList &&
Ratan Gupta06785242019-07-26 22:30:16 +0530972 !userNameAttribute && !groupsAttribute && !serviceEnabled &&
973 !remoteRoleMapData)
Ratan Gupta8a07d282019-03-16 08:33:47 +0530974 {
975 return;
976 }
977
978 // Get the existing resource first then keep modifying
979 // whenever any property gets updated.
Ratan Guptaab828d72019-04-22 14:18:33 +0530980 getLDAPConfigData(serverType, [this, asyncResp, userName, password,
981 baseDNList, userNameAttribute,
982 groupsAttribute, accountProviderType,
Ratan Guptaeb2bbe52019-04-22 14:27:01 +0530983 serviceAddressList, serviceEnabled,
Ratan Gupta06785242019-07-26 22:30:16 +0530984 dbusObjectPath, remoteRoleMapData](
Ratan Guptaab828d72019-04-22 14:18:33 +0530985 bool success, LDAPConfigData confData,
986 const std::string& serverType) {
987 if (!success)
988 {
989 messages::internalError(asyncResp->res);
990 return;
991 }
992 parseLDAPConfigData(asyncResp->res.jsonValue, confData, serverType);
993 if (confData.serviceEnabled)
994 {
995 // Disable the service first and update the rest of
996 // the properties.
997 handleServiceEnablePatch(false, asyncResp, serverType,
Ratan Guptaeb2bbe52019-04-22 14:27:01 +0530998 dbusObjectPath);
Ratan Guptaab828d72019-04-22 14:18:33 +0530999 }
Ratan Gupta8a07d282019-03-16 08:33:47 +05301000
Ratan Guptaab828d72019-04-22 14:18:33 +05301001 if (serviceAddressList)
1002 {
1003 handleServiceAddressPatch(*serviceAddressList, asyncResp,
Ratan Guptaeb2bbe52019-04-22 14:27:01 +05301004 serverType, dbusObjectPath);
Ratan Guptaab828d72019-04-22 14:18:33 +05301005 }
1006 if (userName)
1007 {
1008 handleUserNamePatch(*userName, asyncResp, serverType,
Ratan Guptaeb2bbe52019-04-22 14:27:01 +05301009 dbusObjectPath);
Ratan Guptaab828d72019-04-22 14:18:33 +05301010 }
1011 if (password)
1012 {
1013 handlePasswordPatch(*password, asyncResp, serverType,
Ratan Guptaeb2bbe52019-04-22 14:27:01 +05301014 dbusObjectPath);
Ratan Guptaab828d72019-04-22 14:18:33 +05301015 }
Ratan Gupta8a07d282019-03-16 08:33:47 +05301016
Ratan Guptaab828d72019-04-22 14:18:33 +05301017 if (baseDNList)
1018 {
1019 handleBaseDNPatch(*baseDNList, asyncResp, serverType,
Ratan Guptaeb2bbe52019-04-22 14:27:01 +05301020 dbusObjectPath);
Ratan Guptaab828d72019-04-22 14:18:33 +05301021 }
1022 if (userNameAttribute)
1023 {
1024 handleUserNameAttrPatch(*userNameAttribute, asyncResp,
Ratan Guptaeb2bbe52019-04-22 14:27:01 +05301025 serverType, dbusObjectPath);
Ratan Guptaab828d72019-04-22 14:18:33 +05301026 }
1027 if (groupsAttribute)
1028 {
1029 handleGroupNameAttrPatch(*groupsAttribute, asyncResp,
Ratan Guptaeb2bbe52019-04-22 14:27:01 +05301030 serverType, dbusObjectPath);
Ratan Guptaab828d72019-04-22 14:18:33 +05301031 }
1032 if (serviceEnabled)
1033 {
1034 // if user has given the value as true then enable
1035 // the service. if user has given false then no-op
1036 // as service is already stopped.
1037 if (*serviceEnabled)
Ratan Gupta8a07d282019-03-16 08:33:47 +05301038 {
Ratan Guptaab828d72019-04-22 14:18:33 +05301039 handleServiceEnablePatch(*serviceEnabled, asyncResp,
Ratan Guptaeb2bbe52019-04-22 14:27:01 +05301040 serverType, dbusObjectPath);
Ratan Gupta8a07d282019-03-16 08:33:47 +05301041 }
Ratan Guptaab828d72019-04-22 14:18:33 +05301042 }
1043 else
1044 {
1045 // if user has not given the service enabled value
1046 // then revert it to the same state as it was
1047 // before.
1048 handleServiceEnablePatch(confData.serviceEnabled, asyncResp,
Ratan Guptaeb2bbe52019-04-22 14:27:01 +05301049 serverType, dbusObjectPath);
Ratan Guptaab828d72019-04-22 14:18:33 +05301050 }
Ratan Gupta06785242019-07-26 22:30:16 +05301051
1052 if (remoteRoleMapData)
1053 {
1054 std::vector<nlohmann::json> remoteRoleMap =
1055 std::move(*remoteRoleMapData);
1056
1057 handleRoleMapPatch(asyncResp, confData.groupRoleList,
1058 serverType, remoteRoleMap);
1059 }
Ratan Guptaab828d72019-04-22 14:18:33 +05301060 });
Ratan Gupta8a07d282019-03-16 08:33:47 +05301061 }
Ed Tanousd4b54432019-07-17 22:51:55 +00001062
Ed Tanous1abe55e2018-09-05 08:30:59 -07001063 void doGet(crow::Response& res, const crow::Request& req,
1064 const std::vector<std::string>& params) override
1065 {
AppaRao Puli3d958bb2018-12-25 12:45:54 +05301066 auto asyncResp = std::make_shared<AsyncResp>(res);
1067 res.jsonValue = {
1068 {"@odata.context", "/redfish/v1/"
1069 "$metadata#AccountService.AccountService"},
1070 {"@odata.id", "/redfish/v1/AccountService"},
1071 {"@odata.type", "#AccountService."
Marri Devender Rao37cce912019-02-20 01:05:22 -06001072 "v1_4_0.AccountService"},
AppaRao Puli3d958bb2018-12-25 12:45:54 +05301073 {"Id", "AccountService"},
1074 {"Name", "Account Service"},
1075 {"Description", "Account Service"},
1076 {"ServiceEnabled", true},
AppaRao Puli343ff2e2019-03-24 00:42:13 +05301077 {"MaxPasswordLength", 20},
AppaRao Puli3d958bb2018-12-25 12:45:54 +05301078 {"Accounts",
1079 {{"@odata.id", "/redfish/v1/AccountService/Accounts"}}},
Marri Devender Rao37cce912019-02-20 01:05:22 -06001080 {"Roles", {{"@odata.id", "/redfish/v1/AccountService/Roles"}}},
1081 {"LDAP",
1082 {{"Certificates",
1083 {{"@odata.id",
1084 "/redfish/v1/AccountService/LDAP/Certificates"}}}}}};
AppaRao Puli3d958bb2018-12-25 12:45:54 +05301085 crow::connections::systemBus->async_method_call(
1086 [asyncResp](
1087 const boost::system::error_code ec,
1088 const std::vector<std::pair<
Ed Tanousabf2add2019-01-22 16:40:12 -08001089 std::string, std::variant<uint32_t, uint16_t, uint8_t>>>&
AppaRao Puli3d958bb2018-12-25 12:45:54 +05301090 propertiesList) {
1091 if (ec)
1092 {
1093 messages::internalError(asyncResp->res);
1094 return;
1095 }
1096 BMCWEB_LOG_DEBUG << "Got " << propertiesList.size()
1097 << "properties for AccountService";
1098 for (const std::pair<std::string,
Ed Tanousabf2add2019-01-22 16:40:12 -08001099 std::variant<uint32_t, uint16_t, uint8_t>>&
AppaRao Puli3d958bb2018-12-25 12:45:54 +05301100 property : propertiesList)
1101 {
1102 if (property.first == "MinPasswordLength")
1103 {
1104 const uint8_t* value =
Ed Tanousabf2add2019-01-22 16:40:12 -08001105 std::get_if<uint8_t>(&property.second);
AppaRao Puli3d958bb2018-12-25 12:45:54 +05301106 if (value != nullptr)
1107 {
1108 asyncResp->res.jsonValue["MinPasswordLength"] =
1109 *value;
1110 }
1111 }
1112 if (property.first == "AccountUnlockTimeout")
1113 {
1114 const uint32_t* value =
Ed Tanousabf2add2019-01-22 16:40:12 -08001115 std::get_if<uint32_t>(&property.second);
AppaRao Puli3d958bb2018-12-25 12:45:54 +05301116 if (value != nullptr)
1117 {
1118 asyncResp->res.jsonValue["AccountLockoutDuration"] =
1119 *value;
1120 }
1121 }
1122 if (property.first == "MaxLoginAttemptBeforeLockout")
1123 {
1124 const uint16_t* value =
Ed Tanousabf2add2019-01-22 16:40:12 -08001125 std::get_if<uint16_t>(&property.second);
AppaRao Puli3d958bb2018-12-25 12:45:54 +05301126 if (value != nullptr)
1127 {
1128 asyncResp->res
1129 .jsonValue["AccountLockoutThreshold"] = *value;
1130 }
1131 }
1132 }
1133 },
1134 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
1135 "org.freedesktop.DBus.Properties", "GetAll",
1136 "xyz.openbmc_project.User.AccountPolicy");
Ratan Gupta6973a582018-12-13 18:25:44 +05301137
Ratan Guptaab828d72019-04-22 14:18:33 +05301138 auto callback = [asyncResp](bool success, LDAPConfigData& confData,
1139 const std::string& ldapType) {
1140 parseLDAPConfigData(asyncResp->res.jsonValue, confData, ldapType);
1141 };
1142
1143 getLDAPConfigData("LDAP", callback);
1144 getLDAPConfigData("ActiveDirectory", callback);
AppaRao Puli3d958bb2018-12-25 12:45:54 +05301145 }
Ratan Gupta6973a582018-12-13 18:25:44 +05301146
AppaRao Puli3d958bb2018-12-25 12:45:54 +05301147 void doPatch(crow::Response& res, const crow::Request& req,
1148 const std::vector<std::string>& params) override
1149 {
1150 auto asyncResp = std::make_shared<AsyncResp>(res);
1151
1152 std::optional<uint32_t> unlockTimeout;
1153 std::optional<uint16_t> lockoutThreshold;
Ratan Gupta19fb6e72019-03-04 13:30:50 +05301154 std::optional<uint16_t> minPasswordLength;
1155 std::optional<uint16_t> maxPasswordLength;
Ratan Gupta8a07d282019-03-16 08:33:47 +05301156 std::optional<nlohmann::json> ldapObject;
Ratan Guptaeb2bbe52019-04-22 14:27:01 +05301157 std::optional<nlohmann::json> activeDirectoryObject;
Ratan Gupta19fb6e72019-03-04 13:30:50 +05301158
James Feisteecd51a2019-11-04 21:19:48 +00001159 if (!json_util::readJson(req, res, "AccountLockoutDuration",
1160 unlockTimeout, "AccountLockoutThreshold",
1161 lockoutThreshold, "MaxPasswordLength",
1162 maxPasswordLength, "MinPasswordLength",
1163 minPasswordLength, "LDAP", ldapObject,
1164 "ActiveDirectory", activeDirectoryObject))
AppaRao Puli3d958bb2018-12-25 12:45:54 +05301165 {
1166 return;
1167 }
Ratan Gupta19fb6e72019-03-04 13:30:50 +05301168
1169 if (minPasswordLength)
1170 {
1171 messages::propertyNotWritable(asyncResp->res, "MinPasswordLength");
1172 }
1173
1174 if (maxPasswordLength)
1175 {
1176 messages::propertyNotWritable(asyncResp->res, "MaxPasswordLength");
1177 }
1178
Ratan Gupta8a07d282019-03-16 08:33:47 +05301179 if (ldapObject)
1180 {
1181 handleLDAPPatch(*ldapObject, asyncResp, req, params, "LDAP");
1182 }
1183
Ratan Guptaeb2bbe52019-04-22 14:27:01 +05301184 if (activeDirectoryObject)
1185 {
1186 handleLDAPPatch(*activeDirectoryObject, asyncResp, req, params,
1187 "ActiveDirectory");
1188 }
1189
AppaRao Puli3d958bb2018-12-25 12:45:54 +05301190 if (unlockTimeout)
1191 {
1192 crow::connections::systemBus->async_method_call(
1193 [asyncResp](const boost::system::error_code ec) {
1194 if (ec)
1195 {
1196 messages::internalError(asyncResp->res);
1197 return;
1198 }
Ratan Guptaadd61332019-02-13 20:49:16 +05301199 messages::success(asyncResp->res);
AppaRao Puli3d958bb2018-12-25 12:45:54 +05301200 },
1201 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
1202 "org.freedesktop.DBus.Properties", "Set",
1203 "xyz.openbmc_project.User.AccountPolicy",
Ed Tanousabf2add2019-01-22 16:40:12 -08001204 "AccountUnlockTimeout", std::variant<uint32_t>(*unlockTimeout));
AppaRao Puli3d958bb2018-12-25 12:45:54 +05301205 }
1206 if (lockoutThreshold)
1207 {
1208 crow::connections::systemBus->async_method_call(
1209 [asyncResp](const boost::system::error_code ec) {
1210 if (ec)
1211 {
1212 messages::internalError(asyncResp->res);
1213 return;
1214 }
Ratan Guptaadd61332019-02-13 20:49:16 +05301215 messages::success(asyncResp->res);
AppaRao Puli3d958bb2018-12-25 12:45:54 +05301216 },
1217 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
1218 "org.freedesktop.DBus.Properties", "Set",
1219 "xyz.openbmc_project.User.AccountPolicy",
1220 "MaxLoginAttemptBeforeLockout",
Ed Tanousabf2add2019-01-22 16:40:12 -08001221 std::variant<uint16_t>(*lockoutThreshold));
AppaRao Puli3d958bb2018-12-25 12:45:54 +05301222 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001223 }
Lewanczyk, Dawid88d16c92018-02-02 14:51:09 +01001224};
Tanousf00032d2018-11-05 01:18:10 -03001225
Ed Tanousb9b2e0b2018-09-13 13:47:50 -07001226class AccountsCollection : public Node
1227{
1228 public:
1229 AccountsCollection(CrowApp& app) :
1230 Node(app, "/redfish/v1/AccountService/Accounts/")
1231 {
Ed Tanousb9b2e0b2018-09-13 13:47:50 -07001232 entityPrivileges = {
1233 {boost::beast::http::verb::get,
1234 {{"ConfigureUsers"}, {"ConfigureManager"}}},
1235 {boost::beast::http::verb::head, {{"Login"}}},
1236 {boost::beast::http::verb::patch, {{"ConfigureUsers"}}},
1237 {boost::beast::http::verb::put, {{"ConfigureUsers"}}},
1238 {boost::beast::http::verb::delete_, {{"ConfigureUsers"}}},
1239 {boost::beast::http::verb::post, {{"ConfigureUsers"}}}};
1240 }
1241
1242 private:
1243 void doGet(crow::Response& res, const crow::Request& req,
1244 const std::vector<std::string>& params) override
1245 {
Ed Tanousb9b2e0b2018-09-13 13:47:50 -07001246 auto asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous0f74e642018-11-12 15:17:05 -08001247 res.jsonValue = {{"@odata.context",
1248 "/redfish/v1/"
1249 "$metadata#ManagerAccountCollection."
1250 "ManagerAccountCollection"},
1251 {"@odata.id", "/redfish/v1/AccountService/Accounts"},
1252 {"@odata.type", "#ManagerAccountCollection."
1253 "ManagerAccountCollection"},
1254 {"Name", "Accounts Collection"},
1255 {"Description", "BMC User Accounts"}};
1256
Ed Tanousb9b2e0b2018-09-13 13:47:50 -07001257 crow::connections::systemBus->async_method_call(
1258 [asyncResp](const boost::system::error_code ec,
1259 const ManagedObjectType& users) {
1260 if (ec)
1261 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001262 messages::internalError(asyncResp->res);
Ed Tanousb9b2e0b2018-09-13 13:47:50 -07001263 return;
1264 }
1265
1266 nlohmann::json& memberArray =
1267 asyncResp->res.jsonValue["Members"];
1268 memberArray = nlohmann::json::array();
1269
1270 asyncResp->res.jsonValue["Members@odata.count"] = users.size();
1271 for (auto& user : users)
1272 {
1273 const std::string& path =
1274 static_cast<const std::string&>(user.first);
1275 std::size_t lastIndex = path.rfind("/");
1276 if (lastIndex == std::string::npos)
1277 {
1278 lastIndex = 0;
1279 }
1280 else
1281 {
1282 lastIndex += 1;
1283 }
1284 memberArray.push_back(
1285 {{"@odata.id", "/redfish/v1/AccountService/Accounts/" +
1286 path.substr(lastIndex)}});
1287 }
1288 },
1289 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
1290 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
1291 }
Ed Tanous04ae99e2018-09-20 15:54:36 -07001292 void doPost(crow::Response& res, const crow::Request& req,
1293 const std::vector<std::string>& params) override
1294 {
1295 auto asyncResp = std::make_shared<AsyncResp>(res);
1296
Ed Tanous9712f8a2018-09-21 13:38:49 -07001297 std::string username;
1298 std::string password;
Ed Tanousa24526d2018-12-10 15:17:59 -08001299 std::optional<std::string> roleId("User");
1300 std::optional<bool> enabled = true;
Ed Tanous9712f8a2018-09-21 13:38:49 -07001301 if (!json_util::readJson(req, res, "UserName", username, "Password",
1302 password, "RoleId", roleId, "Enabled",
1303 enabled))
Ed Tanous04ae99e2018-09-20 15:54:36 -07001304 {
1305 return;
1306 }
1307
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -06001308 std::string priv = getPrivilegeFromRoleId(*roleId);
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301309 if (priv.empty())
Ed Tanous04ae99e2018-09-20 15:54:36 -07001310 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001311 messages::propertyValueNotInList(asyncResp->res, *roleId, "RoleId");
Ed Tanous04ae99e2018-09-20 15:54:36 -07001312 return;
1313 }
Ed Tanous9712f8a2018-09-21 13:38:49 -07001314 roleId = priv;
Ed Tanous04ae99e2018-09-20 15:54:36 -07001315
Ayushi Smriti599c71d2019-08-23 17:43:18 +00001316 // Reading AllGroups property
Ed Tanous04ae99e2018-09-20 15:54:36 -07001317 crow::connections::systemBus->async_method_call(
Ayushi Smriti599c71d2019-08-23 17:43:18 +00001318 [asyncResp, username, password{std::move(password)}, roleId,
1319 enabled](const boost::system::error_code ec,
1320 const std::variant<std::vector<std::string>>& allGroups) {
Ed Tanous04ae99e2018-09-20 15:54:36 -07001321 if (ec)
1322 {
Ayushi Smriti599c71d2019-08-23 17:43:18 +00001323 BMCWEB_LOG_DEBUG << "ERROR with async_method_call";
1324 messages::internalError(asyncResp->res);
Ed Tanous04ae99e2018-09-20 15:54:36 -07001325 return;
1326 }
1327
Ayushi Smriti599c71d2019-08-23 17:43:18 +00001328 const std::vector<std::string>* allGroupsList =
1329 std::get_if<std::vector<std::string>>(&allGroups);
1330
1331 if (allGroupsList == nullptr || allGroupsList->empty())
Ed Tanous04ae99e2018-09-20 15:54:36 -07001332 {
Ayushi Smriti599c71d2019-08-23 17:43:18 +00001333 messages::internalError(asyncResp->res);
Ed Tanous04ae99e2018-09-20 15:54:36 -07001334 return;
1335 }
1336
Ayushi Smriti599c71d2019-08-23 17:43:18 +00001337 crow::connections::systemBus->async_method_call(
1338 [asyncResp, username, password{std::move(password)}](
1339 const boost::system::error_code ec) {
1340 if (ec)
1341 {
1342 messages::resourceAlreadyExists(
1343 asyncResp->res,
1344 "#ManagerAccount.v1_0_3.ManagerAccount",
1345 "UserName", username);
1346 return;
1347 }
1348
jayaprakash Mutyala66b5ca72019-08-07 20:26:37 +00001349 if (pamUpdatePassword(username, password) !=
1350 PAM_SUCCESS)
Ayushi Smriti599c71d2019-08-23 17:43:18 +00001351 {
1352 // At this point we have a user that's been created,
1353 // but the password set failed.Something is wrong,
1354 // so delete the user that we've already created
1355 crow::connections::systemBus->async_method_call(
1356 [asyncResp](
1357 const boost::system::error_code ec) {
1358 if (ec)
1359 {
1360 messages::internalError(asyncResp->res);
1361 return;
1362 }
1363
1364 messages::invalidObject(asyncResp->res,
1365 "Password");
1366 },
1367 "xyz.openbmc_project.User.Manager",
1368 "/xyz/openbmc_project/user/" + username,
1369 "xyz.openbmc_project.Object.Delete", "Delete");
1370
1371 BMCWEB_LOG_ERROR << "pamUpdatePassword Failed";
1372 return;
1373 }
1374
1375 messages::created(asyncResp->res);
1376 asyncResp->res.addHeader(
1377 "Location",
1378 "/redfish/v1/AccountService/Accounts/" + username);
1379 },
1380 "xyz.openbmc_project.User.Manager",
1381 "/xyz/openbmc_project/user",
1382 "xyz.openbmc_project.User.Manager", "CreateUser", username,
1383 *allGroupsList, *roleId, *enabled);
Ed Tanous04ae99e2018-09-20 15:54:36 -07001384 },
1385 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
Ayushi Smriti599c71d2019-08-23 17:43:18 +00001386 "org.freedesktop.DBus.Properties", "Get",
1387 "xyz.openbmc_project.User.Manager", "AllGroups");
Ed Tanous04ae99e2018-09-20 15:54:36 -07001388 }
Ed Tanousb9b2e0b2018-09-13 13:47:50 -07001389};
1390
1391class ManagerAccount : public Node
1392{
1393 public:
1394 ManagerAccount(CrowApp& app) :
1395 Node(app, "/redfish/v1/AccountService/Accounts/<str>/", std::string())
1396 {
Ed Tanousb9b2e0b2018-09-13 13:47:50 -07001397 entityPrivileges = {
1398 {boost::beast::http::verb::get,
1399 {{"ConfigureUsers"}, {"ConfigureManager"}, {"ConfigureSelf"}}},
1400 {boost::beast::http::verb::head, {{"Login"}}},
1401 {boost::beast::http::verb::patch, {{"ConfigureUsers"}}},
1402 {boost::beast::http::verb::put, {{"ConfigureUsers"}}},
1403 {boost::beast::http::verb::delete_, {{"ConfigureUsers"}}},
1404 {boost::beast::http::verb::post, {{"ConfigureUsers"}}}};
1405 }
1406
1407 private:
1408 void doGet(crow::Response& res, const crow::Request& req,
1409 const std::vector<std::string>& params) override
1410 {
Ed Tanous0f74e642018-11-12 15:17:05 -08001411
Ed Tanousb9b2e0b2018-09-13 13:47:50 -07001412 auto asyncResp = std::make_shared<AsyncResp>(res);
1413
1414 if (params.size() != 1)
1415 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001416 messages::internalError(asyncResp->res);
Ed Tanousb9b2e0b2018-09-13 13:47:50 -07001417 return;
1418 }
1419
1420 crow::connections::systemBus->async_method_call(
1421 [asyncResp, accountName{std::string(params[0])}](
1422 const boost::system::error_code ec,
1423 const ManagedObjectType& users) {
1424 if (ec)
1425 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001426 messages::internalError(asyncResp->res);
Ed Tanousb9b2e0b2018-09-13 13:47:50 -07001427 return;
1428 }
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301429 auto userIt = users.begin();
Ed Tanousb9b2e0b2018-09-13 13:47:50 -07001430
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301431 for (; userIt != users.end(); userIt++)
Ed Tanousb9b2e0b2018-09-13 13:47:50 -07001432 {
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301433 if (boost::ends_with(userIt->first.str, "/" + accountName))
Ed Tanousb9b2e0b2018-09-13 13:47:50 -07001434 {
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301435 break;
Ed Tanousb9b2e0b2018-09-13 13:47:50 -07001436 }
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301437 }
1438 if (userIt == users.end())
1439 {
1440 messages::resourceNotFound(asyncResp->res, "ManagerAccount",
1441 accountName);
1442 return;
1443 }
Ayushi Smriti4e68c452019-09-04 14:37:55 +05301444
1445 asyncResp->res.jsonValue = {
1446 {"@odata.context",
1447 "/redfish/v1/$metadata#ManagerAccount.ManagerAccount"},
1448 {"@odata.type", "#ManagerAccount.v1_0_3.ManagerAccount"},
1449 {"Name", "User Account"},
1450 {"Description", "User Account"},
1451 {"Password", nullptr}};
1452
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301453 for (const auto& interface : userIt->second)
1454 {
1455 if (interface.first ==
1456 "xyz.openbmc_project.User.Attributes")
Ed Tanousb9b2e0b2018-09-13 13:47:50 -07001457 {
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301458 for (const auto& property : interface.second)
Ed Tanous65b0dc32018-09-19 16:04:03 -07001459 {
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301460 if (property.first == "UserEnabled")
Ed Tanous65b0dc32018-09-19 16:04:03 -07001461 {
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301462 const bool* userEnabled =
Ed Tanousabf2add2019-01-22 16:40:12 -08001463 std::get_if<bool>(&property.second);
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301464 if (userEnabled == nullptr)
Ed Tanous65b0dc32018-09-19 16:04:03 -07001465 {
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301466 BMCWEB_LOG_ERROR
1467 << "UserEnabled wasn't a bool";
1468 messages::internalError(asyncResp->res);
1469 return;
Ed Tanous65b0dc32018-09-19 16:04:03 -07001470 }
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301471 asyncResp->res.jsonValue["Enabled"] =
1472 *userEnabled;
1473 }
1474 else if (property.first ==
1475 "UserLockedForFailedAttempt")
1476 {
1477 const bool* userLocked =
Ed Tanousabf2add2019-01-22 16:40:12 -08001478 std::get_if<bool>(&property.second);
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301479 if (userLocked == nullptr)
1480 {
1481 BMCWEB_LOG_ERROR << "UserLockedForF"
1482 "ailedAttempt "
1483 "wasn't a bool";
1484 messages::internalError(asyncResp->res);
1485 return;
1486 }
1487 asyncResp->res.jsonValue["Locked"] =
1488 *userLocked;
Ratan Gupta24c85422019-01-30 19:41:24 +05301489 asyncResp->res.jsonValue
1490 ["Locked@Redfish.AllowableValues"] = {
Gunnar Mills4d64ce32019-03-29 16:34:56 -05001491 "false"};
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301492 }
1493 else if (property.first == "UserPrivilege")
1494 {
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -06001495 const std::string* userPrivPtr =
Ed Tanousabf2add2019-01-22 16:40:12 -08001496 std::get_if<std::string>(&property.second);
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -06001497 if (userPrivPtr == nullptr)
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301498 {
1499 BMCWEB_LOG_ERROR
1500 << "UserPrivilege wasn't a "
1501 "string";
1502 messages::internalError(asyncResp->res);
1503 return;
1504 }
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -06001505 std::string role =
1506 getRoleIdFromPrivilege(*userPrivPtr);
1507 if (role.empty())
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301508 {
1509 BMCWEB_LOG_ERROR << "Invalid user role";
1510 messages::internalError(asyncResp->res);
1511 return;
1512 }
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -06001513 asyncResp->res.jsonValue["RoleId"] = role;
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301514
1515 asyncResp->res.jsonValue["Links"]["Role"] = {
1516 {"@odata.id", "/redfish/v1/AccountService/"
1517 "Roles/" +
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -06001518 role}};
Ed Tanous65b0dc32018-09-19 16:04:03 -07001519 }
1520 }
Ed Tanousb9b2e0b2018-09-13 13:47:50 -07001521 }
1522 }
1523
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301524 asyncResp->res.jsonValue["@odata.id"] =
1525 "/redfish/v1/AccountService/Accounts/" + accountName;
1526 asyncResp->res.jsonValue["Id"] = accountName;
1527 asyncResp->res.jsonValue["UserName"] = accountName;
Ed Tanousb9b2e0b2018-09-13 13:47:50 -07001528 },
1529 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
1530 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
1531 }
Ed Tanousa8408792018-09-05 16:08:38 -07001532
1533 void doPatch(crow::Response& res, const crow::Request& req,
1534 const std::vector<std::string>& params) override
1535 {
1536 auto asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanousa8408792018-09-05 16:08:38 -07001537 if (params.size() != 1)
1538 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001539 messages::internalError(asyncResp->res);
Ed Tanousa8408792018-09-05 16:08:38 -07001540 return;
1541 }
1542
Ed Tanousa24526d2018-12-10 15:17:59 -08001543 std::optional<std::string> newUserName;
1544 std::optional<std::string> password;
1545 std::optional<bool> enabled;
1546 std::optional<std::string> roleId;
Ratan Gupta24c85422019-01-30 19:41:24 +05301547 std::optional<bool> locked;
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301548 if (!json_util::readJson(req, res, "UserName", newUserName, "Password",
Ratan Gupta24c85422019-01-30 19:41:24 +05301549 password, "RoleId", roleId, "Enabled", enabled,
1550 "Locked", locked))
Ed Tanousa8408792018-09-05 16:08:38 -07001551 {
1552 return;
1553 }
1554
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301555 const std::string& username = params[0];
Ed Tanousa8408792018-09-05 16:08:38 -07001556
jayaprakash Mutyala66b5ca72019-08-07 20:26:37 +00001557 // if user name is not provided in the patch method or if it
1558 // matches the user name in the URI, then we are treating it as updating
1559 // user properties other then username. If username provided doesn't
1560 // match the URI, then we are treating this as user rename request.
1561 if (!newUserName || (newUserName.value() == username))
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301562 {
Ratan Gupta24c85422019-01-30 19:41:24 +05301563 updateUserProperties(asyncResp, username, password, enabled, roleId,
1564 locked);
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301565 return;
1566 }
1567 else
1568 {
1569 crow::connections::systemBus->async_method_call(
1570 [this, asyncResp, username, password(std::move(password)),
1571 roleId(std::move(roleId)), enabled(std::move(enabled)),
jayaprakash Mutyala66b5ca72019-08-07 20:26:37 +00001572 newUser{std::string(*newUserName)},
1573 locked(std::move(locked))](const boost::system::error_code ec,
1574 sdbusplus::message::message& m) {
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301575 if (ec)
Ed Tanousa8408792018-09-05 16:08:38 -07001576 {
jayaprakash Mutyala66b5ca72019-08-07 20:26:37 +00001577 userErrorMessageHandler(m.get_error(), asyncResp,
1578 newUser, username);
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301579 return;
1580 }
1581
1582 updateUserProperties(asyncResp, newUser, password, enabled,
Ratan Gupta24c85422019-01-30 19:41:24 +05301583 roleId, locked);
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301584 },
1585 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
1586 "xyz.openbmc_project.User.Manager", "RenameUser", username,
1587 *newUserName);
1588 }
1589 }
1590
1591 void updateUserProperties(std::shared_ptr<AsyncResp> asyncResp,
1592 const std::string& username,
Ed Tanousa24526d2018-12-10 15:17:59 -08001593 std::optional<std::string> password,
1594 std::optional<bool> enabled,
Ratan Gupta24c85422019-01-30 19:41:24 +05301595 std::optional<std::string> roleId,
1596 std::optional<bool> locked)
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301597 {
Ratan Gupta24c85422019-01-30 19:41:24 +05301598 std::string dbusObjectPath = "/xyz/openbmc_project/user/" + username;
1599 dbus::utility::escapePathForDbus(dbusObjectPath);
1600
Ratan Gupta22c33712019-05-03 21:50:28 +05301601 dbus::utility::checkDbusPathExists(
Ratan Gupta24c85422019-01-30 19:41:24 +05301602 dbusObjectPath,
1603 [dbusObjectPath(std::move(dbusObjectPath)), username,
1604 password(std::move(password)), roleId(std::move(roleId)),
1605 enabled(std::move(enabled)), locked(std::move(locked)),
1606 asyncResp{std::move(asyncResp)}](int rc) {
1607 if (!rc)
1608 {
jayaprakash Mutyala66b5ca72019-08-07 20:26:37 +00001609 messages::resourceNotFound(
1610 asyncResp->res, "#ManagerAccount.v1_0_3.ManagerAccount",
1611 username);
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301612 return;
Ratan Gupta24c85422019-01-30 19:41:24 +05301613 }
jayaprakash Mutyala66b5ca72019-08-07 20:26:37 +00001614
1615 if (password)
1616 {
1617 int retval = pamUpdatePassword(username, *password);
1618
1619 if (retval == PAM_USER_UNKNOWN)
1620 {
1621 messages::resourceNotFound(
1622 asyncResp->res,
1623 "#ManagerAccount.v1_0_3.ManagerAccount", username);
1624 }
1625 else if (retval == PAM_AUTHTOK_ERR)
1626 {
1627 // If password is invalid
1628 messages::propertyValueFormatError(
1629 asyncResp->res, *password, "Password");
1630 BMCWEB_LOG_ERROR << "pamUpdatePassword Failed";
1631 }
1632 else if (retval != PAM_SUCCESS)
1633 {
1634 messages::internalError(asyncResp->res);
1635 return;
1636 }
1637 }
1638
Ratan Gupta24c85422019-01-30 19:41:24 +05301639 if (enabled)
1640 {
1641 crow::connections::systemBus->async_method_call(
1642 [asyncResp](const boost::system::error_code ec) {
1643 if (ec)
1644 {
1645 BMCWEB_LOG_ERROR << "D-Bus responses error: "
1646 << ec;
1647 messages::internalError(asyncResp->res);
1648 return;
1649 }
1650 messages::success(asyncResp->res);
1651 return;
1652 },
1653 "xyz.openbmc_project.User.Manager",
1654 dbusObjectPath.c_str(),
1655 "org.freedesktop.DBus.Properties", "Set",
1656 "xyz.openbmc_project.User.Attributes", "UserEnabled",
1657 std::variant<bool>{*enabled});
1658 }
Ed Tanous9712f8a2018-09-21 13:38:49 -07001659
Ratan Gupta24c85422019-01-30 19:41:24 +05301660 if (roleId)
1661 {
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -06001662 std::string priv = getPrivilegeFromRoleId(*roleId);
Ratan Gupta24c85422019-01-30 19:41:24 +05301663 if (priv.empty())
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301664 {
Ratan Gupta24c85422019-01-30 19:41:24 +05301665 messages::propertyValueNotInList(asyncResp->res,
1666 *roleId, "RoleId");
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301667 return;
1668 }
Ratan Gupta24c85422019-01-30 19:41:24 +05301669
1670 crow::connections::systemBus->async_method_call(
1671 [asyncResp](const boost::system::error_code ec) {
1672 if (ec)
1673 {
1674 BMCWEB_LOG_ERROR << "D-Bus responses error: "
1675 << ec;
1676 messages::internalError(asyncResp->res);
1677 return;
1678 }
1679 messages::success(asyncResp->res);
1680 },
1681 "xyz.openbmc_project.User.Manager",
1682 dbusObjectPath.c_str(),
1683 "org.freedesktop.DBus.Properties", "Set",
1684 "xyz.openbmc_project.User.Attributes", "UserPrivilege",
1685 std::variant<std::string>{priv});
1686 }
1687
1688 if (locked)
1689 {
1690 // admin can unlock the account which is locked by
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -06001691 // successive authentication failures but admin should
1692 // not be allowed to lock an account.
Ratan Gupta24c85422019-01-30 19:41:24 +05301693 if (*locked)
1694 {
1695 messages::propertyValueNotInList(asyncResp->res, "true",
1696 "Locked");
1697 return;
1698 }
1699
1700 crow::connections::systemBus->async_method_call(
1701 [asyncResp](const boost::system::error_code ec) {
1702 if (ec)
1703 {
1704 BMCWEB_LOG_ERROR << "D-Bus responses error: "
1705 << ec;
1706 messages::internalError(asyncResp->res);
1707 return;
1708 }
1709 messages::success(asyncResp->res);
1710 return;
1711 },
1712 "xyz.openbmc_project.User.Manager",
1713 dbusObjectPath.c_str(),
1714 "org.freedesktop.DBus.Properties", "Set",
1715 "xyz.openbmc_project.User.Attributes",
1716 "UserLockedForFailedAttempt",
1717 sdbusplus::message::variant<bool>{*locked});
1718 }
1719 });
Ed Tanousa8408792018-09-05 16:08:38 -07001720 }
Ed Tanous06e086d2018-09-19 17:19:52 -07001721
1722 void doDelete(crow::Response& res, const crow::Request& req,
1723 const std::vector<std::string>& params) override
1724 {
1725 auto asyncResp = std::make_shared<AsyncResp>(res);
1726
1727 if (params.size() != 1)
1728 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001729 messages::internalError(asyncResp->res);
Ed Tanous06e086d2018-09-19 17:19:52 -07001730 return;
1731 }
1732
1733 const std::string userPath = "/xyz/openbmc_project/user/" + params[0];
1734
1735 crow::connections::systemBus->async_method_call(
1736 [asyncResp, username{std::move(params[0])}](
1737 const boost::system::error_code ec) {
1738 if (ec)
1739 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001740 messages::resourceNotFound(
1741 asyncResp->res, "#ManagerAccount.v1_0_3.ManagerAccount",
1742 username);
Ed Tanous06e086d2018-09-19 17:19:52 -07001743 return;
1744 }
1745
Jason M. Billsf12894f2018-10-09 12:45:45 -07001746 messages::accountRemoved(asyncResp->res);
Ed Tanous06e086d2018-09-19 17:19:52 -07001747 },
1748 "xyz.openbmc_project.User.Manager", userPath,
1749 "xyz.openbmc_project.Object.Delete", "Delete");
1750 }
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301751};
Lewanczyk, Dawid88d16c92018-02-02 14:51:09 +01001752
Ed Tanous1abe55e2018-09-05 08:30:59 -07001753} // namespace redfish