blob: 8ccab655ca67329d86484258e37eea0684943b45 [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
John Edward Broadbent7e860f12021-04-08 15:57:16 -070018#include <app.hpp>
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 Tanous52cc1122020-07-18 13:51:21 -070022#include <persistent_data.hpp>
Ed Tanous45ca1b82022-03-25 13:07:27 -070023#include <query.hpp>
Ed Tanoused398212021-06-09 17:05:54 -070024#include <registries/privilege_registry.hpp>
Jonathan Doman1e1e5982021-06-11 09:36:17 -070025#include <sdbusplus/asio/property.hpp>
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +020026#include <sdbusplus/unpack_properties.hpp>
27#include <utils/dbus_utils.hpp>
Ed Tanousa8408792018-09-05 16:08:38 -070028#include <utils/json_utils.hpp>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050029
Abhishek Patelc7229812022-02-01 10:07:15 -060030#include <optional>
31#include <string>
32#include <vector>
33
Ed Tanous1abe55e2018-09-05 08:30:59 -070034namespace redfish
35{
Lewanczyk, Dawid88d16c92018-02-02 14:51:09 +010036
Ed Tanous23a21a12020-07-25 04:45:05 +000037constexpr const char* ldapConfigObjectName =
Ratan Gupta6973a582018-12-13 18:25:44 +053038 "/xyz/openbmc_project/user/ldap/openldap";
Ed Tanous2c70f802020-09-28 14:29:23 -070039constexpr const char* adConfigObject =
Ratan Guptaab828d72019-04-22 14:18:33 +053040 "/xyz/openbmc_project/user/ldap/active_directory";
41
P Dheeraj Srujan Kumarb477fd42021-12-16 07:17:51 +053042constexpr const char* rootUserDbusPath = "/xyz/openbmc_project/user/";
Ratan Gupta6973a582018-12-13 18:25:44 +053043constexpr const char* ldapRootObject = "/xyz/openbmc_project/user/ldap";
44constexpr const char* ldapDbusService = "xyz.openbmc_project.Ldap.Config";
45constexpr const char* ldapConfigInterface =
46 "xyz.openbmc_project.User.Ldap.Config";
47constexpr const char* ldapCreateInterface =
48 "xyz.openbmc_project.User.Ldap.Create";
49constexpr const char* ldapEnableInterface = "xyz.openbmc_project.Object.Enable";
Ratan Gupta06785242019-07-26 22:30:16 +053050constexpr const char* ldapPrivMapperInterface =
51 "xyz.openbmc_project.User.PrivilegeMapper";
Ratan Gupta6973a582018-12-13 18:25:44 +053052constexpr const char* dbusObjManagerIntf = "org.freedesktop.DBus.ObjectManager";
53constexpr const char* propertyInterface = "org.freedesktop.DBus.Properties";
54constexpr const char* mapperBusName = "xyz.openbmc_project.ObjectMapper";
55constexpr const char* mapperObjectPath = "/xyz/openbmc_project/object_mapper";
56constexpr const char* mapperIntf = "xyz.openbmc_project.ObjectMapper";
57
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -060058struct LDAPRoleMapData
59{
60 std::string groupName;
61 std::string privilege;
62};
63
Ratan Gupta6973a582018-12-13 18:25:44 +053064struct LDAPConfigData
65{
66 std::string uri{};
67 std::string bindDN{};
68 std::string baseDN{};
69 std::string searchScope{};
70 std::string serverType{};
71 bool serviceEnabled = false;
72 std::string userNameAttribute{};
73 std::string groupAttribute{};
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -060074 std::vector<std::pair<std::string, LDAPRoleMapData>> groupRoleList;
Ratan Gupta6973a582018-12-13 18:25:44 +053075};
76
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -060077inline std::string getRoleIdFromPrivilege(std::string_view role)
AppaRao Puli84e12cb2018-10-11 01:28:15 +053078{
79 if (role == "priv-admin")
80 {
81 return "Administrator";
82 }
Ed Tanous3174e4d2020-10-07 11:41:22 -070083 if (role == "priv-user")
AppaRao Puli84e12cb2018-10-11 01:28:15 +053084 {
AppaRao Pulic80fee52019-10-16 14:49:36 +053085 return "ReadOnly";
AppaRao Puli84e12cb2018-10-11 01:28:15 +053086 }
Ed Tanous3174e4d2020-10-07 11:41:22 -070087 if (role == "priv-operator")
AppaRao Puli84e12cb2018-10-11 01:28:15 +053088 {
89 return "Operator";
90 }
91 return "";
92}
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -060093inline std::string getPrivilegeFromRoleId(std::string_view role)
AppaRao Puli84e12cb2018-10-11 01:28:15 +053094{
95 if (role == "Administrator")
96 {
97 return "priv-admin";
98 }
Ed Tanous3174e4d2020-10-07 11:41:22 -070099 if (role == "ReadOnly")
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530100 {
101 return "priv-user";
102 }
Ed Tanous3174e4d2020-10-07 11:41:22 -0700103 if (role == "Operator")
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530104 {
105 return "priv-operator";
106 }
107 return "";
108}
Ed Tanousb9b2e0b2018-09-13 13:47:50 -0700109
Abhishek Patelc7229812022-02-01 10:07:15 -0600110/**
111 * @brief Maps user group names retrieved from D-Bus object to
112 * Account Types.
113 *
114 * @param[in] userGroups List of User groups
115 * @param[out] res AccountTypes populated
116 *
117 * @return true in case of success, false if UserGroups contains
118 * invalid group name(s).
119 */
120inline bool translateUserGroup(const std::vector<std::string>& userGroups,
121 crow::Response& res)
122{
123 std::vector<std::string> accountTypes;
124 for (const auto& userGroup : userGroups)
125 {
126 if (userGroup == "redfish")
127 {
128 accountTypes.emplace_back("Redfish");
129 accountTypes.emplace_back("WebUI");
130 }
131 else if (userGroup == "ipmi")
132 {
133 accountTypes.emplace_back("IPMI");
134 }
135 else if (userGroup == "ssh")
136 {
137 accountTypes.emplace_back("HostConsole");
138 accountTypes.emplace_back("ManagerConsole");
139 }
140 else if (userGroup == "web")
141 {
142 // 'web' is one of the valid groups in the UserGroups property of
143 // the user account in the D-Bus object. This group is currently not
144 // doing anything, and is considered to be equivalent to 'redfish'.
145 // 'redfish' user group is mapped to 'Redfish'and 'WebUI'
146 // AccountTypes, so do nothing here...
147 }
148 else
149 {
150 // Invalid user group name. Caller throws an excption.
151 return false;
152 }
153 }
154
155 res.jsonValue["AccountTypes"] = std::move(accountTypes);
156 return true;
157}
158
zhanghch058d1b46d2021-04-01 11:18:24 +0800159inline void userErrorMessageHandler(
160 const sd_bus_error* e, const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
161 const std::string& newUser, const std::string& username)
jayaprakash Mutyala66b5ca72019-08-07 20:26:37 +0000162{
jayaprakash Mutyala66b5ca72019-08-07 20:26:37 +0000163 if (e == nullptr)
164 {
165 messages::internalError(asyncResp->res);
166 return;
167 }
168
Manojkiran Eda055806b2020-11-03 09:36:28 +0530169 const char* errorMessage = e->name;
jayaprakash Mutyala66b5ca72019-08-07 20:26:37 +0000170 if (strcmp(errorMessage,
171 "xyz.openbmc_project.User.Common.Error.UserNameExists") == 0)
172 {
Jiaqing Zhaod8a5d5d2022-08-05 16:21:51 +0800173 messages::resourceAlreadyExists(asyncResp->res, "ManagerAccount",
jayaprakash Mutyala66b5ca72019-08-07 20:26:37 +0000174 "UserName", newUser);
175 }
176 else if (strcmp(errorMessage, "xyz.openbmc_project.User.Common.Error."
177 "UserNameDoesNotExist") == 0)
178 {
Jiaqing Zhaod8a5d5d2022-08-05 16:21:51 +0800179 messages::resourceNotFound(asyncResp->res, "ManagerAccount", username);
jayaprakash Mutyala66b5ca72019-08-07 20:26:37 +0000180 }
Ed Tanousd4d25792020-09-29 15:15:03 -0700181 else if ((strcmp(errorMessage,
182 "xyz.openbmc_project.Common.Error.InvalidArgument") ==
183 0) ||
George Liu0fda0f12021-11-16 10:06:17 +0800184 (strcmp(
185 errorMessage,
186 "xyz.openbmc_project.User.Common.Error.UserNameGroupFail") ==
187 0))
jayaprakash Mutyala66b5ca72019-08-07 20:26:37 +0000188 {
189 messages::propertyValueFormatError(asyncResp->res, newUser, "UserName");
190 }
191 else if (strcmp(errorMessage,
192 "xyz.openbmc_project.User.Common.Error.NoResource") == 0)
193 {
194 messages::createLimitReachedForResource(asyncResp->res);
195 }
jayaprakash Mutyala66b5ca72019-08-07 20:26:37 +0000196 else
197 {
198 messages::internalError(asyncResp->res);
199 }
jayaprakash Mutyala66b5ca72019-08-07 20:26:37 +0000200}
201
Ed Tanous81ce6092020-12-17 16:54:55 +0000202inline void parseLDAPConfigData(nlohmann::json& jsonResponse,
Ed Tanous23a21a12020-07-25 04:45:05 +0000203 const LDAPConfigData& confData,
204 const std::string& ldapType)
Ratan Gupta6973a582018-12-13 18:25:44 +0530205{
Ratan Guptaab828d72019-04-22 14:18:33 +0530206 std::string service =
207 (ldapType == "LDAP") ? "LDAPService" : "ActiveDirectoryService";
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600208
Ed Tanous14766872022-03-15 10:44:42 -0700209 nlohmann::json& ldap = jsonResponse[ldapType];
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600210
Ed Tanous14766872022-03-15 10:44:42 -0700211 ldap["ServiceEnabled"] = confData.serviceEnabled;
212 ldap["ServiceAddresses"] = nlohmann::json::array({confData.uri});
213 ldap["Authentication"]["AuthenticationType"] = "UsernameAndPassword";
214 ldap["Authentication"]["Username"] = confData.bindDN;
215 ldap["Authentication"]["Password"] = nullptr;
216
217 ldap["LDAPService"]["SearchSettings"]["BaseDistinguishedNames"] =
218 nlohmann::json::array({confData.baseDN});
219 ldap["LDAPService"]["SearchSettings"]["UsernameAttribute"] =
220 confData.userNameAttribute;
221 ldap["LDAPService"]["SearchSettings"]["GroupsAttribute"] =
222 confData.groupAttribute;
223
224 nlohmann::json& roleMapArray = ldap["RemoteRoleMapping"];
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600225 roleMapArray = nlohmann::json::array();
Ed Tanous9eb808c2022-01-25 10:19:23 -0800226 for (const auto& obj : confData.groupRoleList)
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600227 {
228 BMCWEB_LOG_DEBUG << "Pushing the data groupName="
229 << obj.second.groupName << "\n";
Ed Tanous613dabe2022-07-09 11:17:36 -0700230
231 nlohmann::json::array_t remoteGroupArray;
232 nlohmann::json::object_t remoteGroup;
233 remoteGroup["RemoteGroup"] = obj.second.groupName;
234 remoteGroupArray.emplace_back(std::move(remoteGroup));
235 roleMapArray.emplace_back(std::move(remoteGroupArray));
236
237 nlohmann::json::array_t localRoleArray;
238 nlohmann::json::object_t localRole;
239 localRole["LocalRole"] = getRoleIdFromPrivilege(obj.second.privilege);
240 localRoleArray.emplace_back(std::move(localRole));
241 roleMapArray.emplace_back(std::move(localRoleArray));
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600242 }
Ratan Gupta6973a582018-12-13 18:25:44 +0530243}
244
245/**
Ratan Gupta06785242019-07-26 22:30:16 +0530246 * @brief validates given JSON input and then calls appropriate method to
247 * create, to delete or to set Rolemapping object based on the given input.
248 *
249 */
Ed Tanous23a21a12020-07-25 04:45:05 +0000250inline void handleRoleMapPatch(
zhanghch058d1b46d2021-04-01 11:18:24 +0800251 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ratan Gupta06785242019-07-26 22:30:16 +0530252 const std::vector<std::pair<std::string, LDAPRoleMapData>>& roleMapObjData,
Ed Tanousf23b7292020-10-15 09:41:17 -0700253 const std::string& serverType, const std::vector<nlohmann::json>& input)
Ratan Gupta06785242019-07-26 22:30:16 +0530254{
255 for (size_t index = 0; index < input.size(); index++)
256 {
Ed Tanousf23b7292020-10-15 09:41:17 -0700257 const nlohmann::json& thisJson = input[index];
Ratan Gupta06785242019-07-26 22:30:16 +0530258
259 if (thisJson.is_null())
260 {
261 // delete the existing object
262 if (index < roleMapObjData.size())
263 {
264 crow::connections::systemBus->async_method_call(
265 [asyncResp, roleMapObjData, serverType,
266 index](const boost::system::error_code ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700267 if (ec)
268 {
269 BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
270 messages::internalError(asyncResp->res);
271 return;
272 }
273 asyncResp->res
274 .jsonValue[serverType]["RemoteRoleMapping"][index] =
275 nullptr;
Ratan Gupta06785242019-07-26 22:30:16 +0530276 },
277 ldapDbusService, roleMapObjData[index].first,
278 "xyz.openbmc_project.Object.Delete", "Delete");
279 }
280 else
281 {
282 BMCWEB_LOG_ERROR << "Can't delete the object";
283 messages::propertyValueTypeError(
Ed Tanous71f52d92021-02-19 08:51:17 -0800284 asyncResp->res,
285 thisJson.dump(2, ' ', true,
286 nlohmann::json::error_handler_t::replace),
Ratan Gupta06785242019-07-26 22:30:16 +0530287 "RemoteRoleMapping/" + std::to_string(index));
288 return;
289 }
290 }
291 else if (thisJson.empty())
292 {
293 // Don't do anything for the empty objects,parse next json
294 // eg {"RemoteRoleMapping",[{}]}
295 }
296 else
297 {
298 // update/create the object
299 std::optional<std::string> remoteGroup;
300 std::optional<std::string> localRole;
301
Ed Tanousf23b7292020-10-15 09:41:17 -0700302 // This is a copy, but it's required in this case because of how
303 // readJson is structured
304 nlohmann::json thisJsonCopy = thisJson;
305 if (!json_util::readJson(thisJsonCopy, asyncResp->res,
306 "RemoteGroup", remoteGroup, "LocalRole",
307 localRole))
Ratan Gupta06785242019-07-26 22:30:16 +0530308 {
309 continue;
310 }
311
312 // Update existing RoleMapping Object
313 if (index < roleMapObjData.size())
314 {
315 BMCWEB_LOG_DEBUG << "Update Role Map Object";
316 // If "RemoteGroup" info is provided
317 if (remoteGroup)
318 {
319 crow::connections::systemBus->async_method_call(
320 [asyncResp, roleMapObjData, serverType, index,
321 remoteGroup](const boost::system::error_code ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700322 if (ec)
323 {
324 BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
325 messages::internalError(asyncResp->res);
326 return;
327 }
328 asyncResp->res
329 .jsonValue[serverType]["RemoteRoleMapping"][index]
330 ["RemoteGroup"] = *remoteGroup;
Ratan Gupta06785242019-07-26 22:30:16 +0530331 },
332 ldapDbusService, roleMapObjData[index].first,
333 propertyInterface, "Set",
334 "xyz.openbmc_project.User.PrivilegeMapperEntry",
335 "GroupName",
Ed Tanous168e20c2021-12-13 14:39:53 -0800336 dbus::utility::DbusVariantType(
337 std::move(*remoteGroup)));
Ratan Gupta06785242019-07-26 22:30:16 +0530338 }
339
340 // If "LocalRole" info is provided
341 if (localRole)
342 {
343 crow::connections::systemBus->async_method_call(
344 [asyncResp, roleMapObjData, serverType, index,
345 localRole](const boost::system::error_code ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700346 if (ec)
347 {
348 BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
349 messages::internalError(asyncResp->res);
350 return;
351 }
352 asyncResp->res
353 .jsonValue[serverType]["RemoteRoleMapping"][index]
354 ["LocalRole"] = *localRole;
Ratan Gupta06785242019-07-26 22:30:16 +0530355 },
356 ldapDbusService, roleMapObjData[index].first,
357 propertyInterface, "Set",
358 "xyz.openbmc_project.User.PrivilegeMapperEntry",
359 "Privilege",
Ed Tanous168e20c2021-12-13 14:39:53 -0800360 dbus::utility::DbusVariantType(
Ratan Gupta06785242019-07-26 22:30:16 +0530361 getPrivilegeFromRoleId(std::move(*localRole))));
362 }
363 }
364 // Create a new RoleMapping Object.
365 else
366 {
367 BMCWEB_LOG_DEBUG
368 << "setRoleMappingProperties: Creating new Object";
369 std::string pathString =
370 "RemoteRoleMapping/" + std::to_string(index);
371
372 if (!localRole)
373 {
374 messages::propertyMissing(asyncResp->res,
375 pathString + "/LocalRole");
376 continue;
377 }
378 if (!remoteGroup)
379 {
380 messages::propertyMissing(asyncResp->res,
381 pathString + "/RemoteGroup");
382 continue;
383 }
384
385 std::string dbusObjectPath;
386 if (serverType == "ActiveDirectory")
387 {
Ed Tanous2c70f802020-09-28 14:29:23 -0700388 dbusObjectPath = adConfigObject;
Ratan Gupta06785242019-07-26 22:30:16 +0530389 }
390 else if (serverType == "LDAP")
391 {
Ed Tanous23a21a12020-07-25 04:45:05 +0000392 dbusObjectPath = ldapConfigObjectName;
Ratan Gupta06785242019-07-26 22:30:16 +0530393 }
394
395 BMCWEB_LOG_DEBUG << "Remote Group=" << *remoteGroup
396 << ",LocalRole=" << *localRole;
397
398 crow::connections::systemBus->async_method_call(
Ed Tanous271584a2019-07-09 16:24:22 -0700399 [asyncResp, serverType, localRole,
Ratan Gupta06785242019-07-26 22:30:16 +0530400 remoteGroup](const boost::system::error_code ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700401 if (ec)
402 {
403 BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
404 messages::internalError(asyncResp->res);
405 return;
406 }
407 nlohmann::json& remoteRoleJson =
408 asyncResp->res
409 .jsonValue[serverType]["RemoteRoleMapping"];
410 nlohmann::json::object_t roleMapEntry;
411 roleMapEntry["LocalRole"] = *localRole;
412 roleMapEntry["RemoteGroup"] = *remoteGroup;
413 remoteRoleJson.push_back(std::move(roleMapEntry));
Ratan Gupta06785242019-07-26 22:30:16 +0530414 },
415 ldapDbusService, dbusObjectPath, ldapPrivMapperInterface,
Ed Tanous3174e4d2020-10-07 11:41:22 -0700416 "Create", *remoteGroup,
Ratan Gupta06785242019-07-26 22:30:16 +0530417 getPrivilegeFromRoleId(std::move(*localRole)));
418 }
419 }
420 }
421}
422
423/**
Ratan Gupta6973a582018-12-13 18:25:44 +0530424 * Function that retrieves all properties for LDAP config object
425 * into JSON
426 */
427template <typename CallbackFunc>
428inline void getLDAPConfigData(const std::string& ldapType,
429 CallbackFunc&& callback)
430{
Ratan Guptaab828d72019-04-22 14:18:33 +0530431
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600432 const std::array<const char*, 2> interfaces = {ldapEnableInterface,
Ratan Gupta6973a582018-12-13 18:25:44 +0530433 ldapConfigInterface};
434
435 crow::connections::systemBus->async_method_call(
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600436 [callback, ldapType](const boost::system::error_code ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800437 const dbus::utility::MapperGetObject& resp) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700438 if (ec || resp.empty())
439 {
440 BMCWEB_LOG_ERROR
441 << "DBUS response error during getting of service name: " << ec;
442 LDAPConfigData empty{};
443 callback(false, empty, ldapType);
444 return;
445 }
446 std::string service = resp.begin()->first;
447 crow::connections::systemBus->async_method_call(
448 [callback,
449 ldapType](const boost::system::error_code errorCode,
450 const dbus::utility::ManagedObjectType& ldapObjects) {
451 LDAPConfigData confData{};
452 if (errorCode)
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600453 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700454 callback(false, confData, ldapType);
455 BMCWEB_LOG_ERROR << "D-Bus responses error: " << errorCode;
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600456 return;
457 }
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600458
Ed Tanous002d39b2022-05-31 08:59:27 -0700459 std::string ldapDbusType;
460 std::string searchString;
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600461
Ed Tanous002d39b2022-05-31 08:59:27 -0700462 if (ldapType == "LDAP")
463 {
464 ldapDbusType =
465 "xyz.openbmc_project.User.Ldap.Config.Type.OpenLdap";
466 searchString = "openldap";
467 }
468 else if (ldapType == "ActiveDirectory")
469 {
470 ldapDbusType =
471 "xyz.openbmc_project.User.Ldap.Config.Type.ActiveDirectory";
472 searchString = "active_directory";
473 }
474 else
475 {
476 BMCWEB_LOG_ERROR << "Can't get the DbusType for the given type="
477 << ldapType;
478 callback(false, confData, ldapType);
479 return;
480 }
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600481
Ed Tanous002d39b2022-05-31 08:59:27 -0700482 std::string ldapEnableInterfaceStr = ldapEnableInterface;
483 std::string ldapConfigInterfaceStr = ldapConfigInterface;
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600484
Ed Tanous002d39b2022-05-31 08:59:27 -0700485 for (const auto& object : ldapObjects)
486 {
487 // let's find the object whose ldap type is equal to the
488 // given type
489 if (object.first.str.find(searchString) == std::string::npos)
490 {
491 continue;
492 }
493
494 for (const auto& interface : object.second)
495 {
496 if (interface.first == ldapEnableInterfaceStr)
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600497 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700498 // rest of the properties are string.
499 for (const auto& property : interface.second)
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600500 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700501 if (property.first == "Enabled")
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600502 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700503 const bool* value =
504 std::get_if<bool>(&property.second);
505 if (value == nullptr)
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600506 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700507 continue;
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600508 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700509 confData.serviceEnabled = *value;
510 break;
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600511 }
512 }
513 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700514 else if (interface.first == ldapConfigInterfaceStr)
515 {
516
517 for (const auto& property : interface.second)
518 {
519 const std::string* strValue =
520 std::get_if<std::string>(&property.second);
521 if (strValue == nullptr)
522 {
523 continue;
524 }
525 if (property.first == "LDAPServerURI")
526 {
527 confData.uri = *strValue;
528 }
529 else if (property.first == "LDAPBindDN")
530 {
531 confData.bindDN = *strValue;
532 }
533 else if (property.first == "LDAPBaseDN")
534 {
535 confData.baseDN = *strValue;
536 }
537 else if (property.first == "LDAPSearchScope")
538 {
539 confData.searchScope = *strValue;
540 }
541 else if (property.first == "GroupNameAttribute")
542 {
543 confData.groupAttribute = *strValue;
544 }
545 else if (property.first == "UserNameAttribute")
546 {
547 confData.userNameAttribute = *strValue;
548 }
549 else if (property.first == "LDAPType")
550 {
551 confData.serverType = *strValue;
552 }
553 }
554 }
555 else if (interface.first ==
556 "xyz.openbmc_project.User.PrivilegeMapperEntry")
557 {
558 LDAPRoleMapData roleMapData{};
559 for (const auto& property : interface.second)
560 {
561 const std::string* strValue =
562 std::get_if<std::string>(&property.second);
563
564 if (strValue == nullptr)
565 {
566 continue;
567 }
568
569 if (property.first == "GroupName")
570 {
571 roleMapData.groupName = *strValue;
572 }
573 else if (property.first == "Privilege")
574 {
575 roleMapData.privilege = *strValue;
576 }
577 }
578
579 confData.groupRoleList.emplace_back(object.first.str,
580 roleMapData);
581 }
582 }
583 }
584 callback(true, confData, ldapType);
585 },
586 service, ldapRootObject, dbusObjManagerIntf, "GetManagedObjects");
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600587 },
588 mapperBusName, mapperObjectPath, mapperIntf, "GetObject",
Ed Tanous23a21a12020-07-25 04:45:05 +0000589 ldapConfigObjectName, interfaces);
Ratan Gupta6973a582018-12-13 18:25:44 +0530590}
591
Ed Tanous6c51eab2021-06-03 12:30:29 -0700592/**
593 * @brief parses the authentication section under the LDAP
594 * @param input JSON data
595 * @param asyncResp pointer to the JSON response
596 * @param userName userName to be filled from the given JSON.
597 * @param password password to be filled from the given JSON.
598 */
Ed Tanous4f48d5f2021-06-21 08:27:45 -0700599inline void parseLDAPAuthenticationJson(
Ed Tanous6c51eab2021-06-03 12:30:29 -0700600 nlohmann::json input, const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
601 std::optional<std::string>& username, std::optional<std::string>& password)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700602{
Ed Tanous6c51eab2021-06-03 12:30:29 -0700603 std::optional<std::string> authType;
604
605 if (!json_util::readJson(input, asyncResp->res, "AuthenticationType",
606 authType, "Username", username, "Password",
607 password))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700608 {
Ed Tanous6c51eab2021-06-03 12:30:29 -0700609 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700610 }
Ed Tanous6c51eab2021-06-03 12:30:29 -0700611 if (!authType)
Ratan Gupta8a07d282019-03-16 08:33:47 +0530612 {
Ed Tanous6c51eab2021-06-03 12:30:29 -0700613 return;
Ratan Gupta8a07d282019-03-16 08:33:47 +0530614 }
Ed Tanous6c51eab2021-06-03 12:30:29 -0700615 if (*authType != "UsernameAndPassword")
Ratan Gupta8a07d282019-03-16 08:33:47 +0530616 {
Ed Tanous6c51eab2021-06-03 12:30:29 -0700617 messages::propertyValueNotInList(asyncResp->res, *authType,
618 "AuthenticationType");
619 return;
Ratan Gupta8a07d282019-03-16 08:33:47 +0530620 }
Ed Tanous6c51eab2021-06-03 12:30:29 -0700621}
622/**
623 * @brief parses the LDAPService section under the LDAP
624 * @param input JSON data
625 * @param asyncResp pointer to the JSON response
626 * @param baseDNList baseDN to be filled from the given JSON.
627 * @param userNameAttribute userName to be filled from the given JSON.
628 * @param groupaAttribute password to be filled from the given JSON.
629 */
Ratan Gupta8a07d282019-03-16 08:33:47 +0530630
Ed Tanous4f48d5f2021-06-21 08:27:45 -0700631inline void
632 parseLDAPServiceJson(nlohmann::json input,
633 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
634 std::optional<std::vector<std::string>>& baseDNList,
635 std::optional<std::string>& userNameAttribute,
636 std::optional<std::string>& groupsAttribute)
Ed Tanous6c51eab2021-06-03 12:30:29 -0700637{
638 std::optional<nlohmann::json> searchSettings;
639
640 if (!json_util::readJson(input, asyncResp->res, "SearchSettings",
641 searchSettings))
Ratan Gupta8a07d282019-03-16 08:33:47 +0530642 {
Ed Tanous6c51eab2021-06-03 12:30:29 -0700643 return;
Ratan Gupta8a07d282019-03-16 08:33:47 +0530644 }
Ed Tanous6c51eab2021-06-03 12:30:29 -0700645 if (!searchSettings)
Ratan Gupta8a07d282019-03-16 08:33:47 +0530646 {
Ed Tanous6c51eab2021-06-03 12:30:29 -0700647 return;
Ratan Gupta8a07d282019-03-16 08:33:47 +0530648 }
Ed Tanous6c51eab2021-06-03 12:30:29 -0700649 if (!json_util::readJson(*searchSettings, asyncResp->res,
650 "BaseDistinguishedNames", baseDNList,
651 "UsernameAttribute", userNameAttribute,
652 "GroupsAttribute", groupsAttribute))
Ratan Gupta8a07d282019-03-16 08:33:47 +0530653 {
Ed Tanous6c51eab2021-06-03 12:30:29 -0700654 return;
Ratan Gupta8a07d282019-03-16 08:33:47 +0530655 }
Ed Tanous6c51eab2021-06-03 12:30:29 -0700656}
657/**
658 * @brief updates the LDAP server address and updates the
659 json response with the new value.
660 * @param serviceAddressList address to be updated.
661 * @param asyncResp pointer to the JSON response
662 * @param ldapServerElementName Type of LDAP
663 server(openLDAP/ActiveDirectory)
664 */
Ratan Gupta8a07d282019-03-16 08:33:47 +0530665
Ed Tanous4f48d5f2021-06-21 08:27:45 -0700666inline void handleServiceAddressPatch(
Ed Tanous6c51eab2021-06-03 12:30:29 -0700667 const std::vector<std::string>& serviceAddressList,
668 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
669 const std::string& ldapServerElementName,
670 const std::string& ldapConfigObject)
671{
672 crow::connections::systemBus->async_method_call(
673 [asyncResp, ldapServerElementName,
674 serviceAddressList](const boost::system::error_code ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700675 if (ec)
676 {
677 BMCWEB_LOG_DEBUG
678 << "Error Occurred in updating the service address";
679 messages::internalError(asyncResp->res);
680 return;
681 }
682 std::vector<std::string> modifiedserviceAddressList = {
683 serviceAddressList.front()};
684 asyncResp->res.jsonValue[ldapServerElementName]["ServiceAddresses"] =
685 modifiedserviceAddressList;
686 if ((serviceAddressList).size() > 1)
687 {
688 messages::propertyValueModified(asyncResp->res, "ServiceAddresses",
689 serviceAddressList.front());
690 }
691 BMCWEB_LOG_DEBUG << "Updated the service address";
Ed Tanous6c51eab2021-06-03 12:30:29 -0700692 },
693 ldapDbusService, ldapConfigObject, propertyInterface, "Set",
694 ldapConfigInterface, "LDAPServerURI",
Ed Tanous168e20c2021-12-13 14:39:53 -0800695 dbus::utility::DbusVariantType(serviceAddressList.front()));
Ed Tanous6c51eab2021-06-03 12:30:29 -0700696}
697/**
698 * @brief updates the LDAP Bind DN and updates the
699 json response with the new value.
700 * @param username name of the user which needs to be updated.
701 * @param asyncResp pointer to the JSON response
702 * @param ldapServerElementName Type of LDAP
703 server(openLDAP/ActiveDirectory)
704 */
Ratan Gupta8a07d282019-03-16 08:33:47 +0530705
Ed Tanous4f48d5f2021-06-21 08:27:45 -0700706inline void
707 handleUserNamePatch(const std::string& username,
708 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
709 const std::string& ldapServerElementName,
710 const std::string& ldapConfigObject)
Ed Tanous6c51eab2021-06-03 12:30:29 -0700711{
712 crow::connections::systemBus->async_method_call(
713 [asyncResp, username,
714 ldapServerElementName](const boost::system::error_code ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700715 if (ec)
716 {
717 BMCWEB_LOG_DEBUG << "Error occurred in updating the username";
718 messages::internalError(asyncResp->res);
719 return;
720 }
721 asyncResp->res
722 .jsonValue[ldapServerElementName]["Authentication"]["Username"] =
723 username;
724 BMCWEB_LOG_DEBUG << "Updated the username";
Ed Tanous6c51eab2021-06-03 12:30:29 -0700725 },
726 ldapDbusService, ldapConfigObject, propertyInterface, "Set",
Ed Tanous168e20c2021-12-13 14:39:53 -0800727 ldapConfigInterface, "LDAPBindDN",
728 dbus::utility::DbusVariantType(username));
Ed Tanous6c51eab2021-06-03 12:30:29 -0700729}
730
731/**
732 * @brief updates the LDAP password
733 * @param password : ldap password which needs to be updated.
734 * @param asyncResp pointer to the JSON response
735 * @param ldapServerElementName Type of LDAP
736 * server(openLDAP/ActiveDirectory)
737 */
738
Ed Tanous4f48d5f2021-06-21 08:27:45 -0700739inline void
740 handlePasswordPatch(const std::string& password,
741 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
742 const std::string& ldapServerElementName,
743 const std::string& ldapConfigObject)
Ed Tanous6c51eab2021-06-03 12:30:29 -0700744{
745 crow::connections::systemBus->async_method_call(
746 [asyncResp, password,
747 ldapServerElementName](const boost::system::error_code ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700748 if (ec)
749 {
750 BMCWEB_LOG_DEBUG << "Error occurred in updating the password";
751 messages::internalError(asyncResp->res);
752 return;
753 }
754 asyncResp->res
755 .jsonValue[ldapServerElementName]["Authentication"]["Password"] =
756 "";
757 BMCWEB_LOG_DEBUG << "Updated the password";
Ed Tanous6c51eab2021-06-03 12:30:29 -0700758 },
759 ldapDbusService, ldapConfigObject, propertyInterface, "Set",
760 ldapConfigInterface, "LDAPBindDNPassword",
Ed Tanous168e20c2021-12-13 14:39:53 -0800761 dbus::utility::DbusVariantType(password));
Ed Tanous6c51eab2021-06-03 12:30:29 -0700762}
763
764/**
765 * @brief updates the LDAP BaseDN and updates the
766 json response with the new value.
767 * @param baseDNList baseDN list which needs to be updated.
768 * @param asyncResp pointer to the JSON response
769 * @param ldapServerElementName Type of LDAP
770 server(openLDAP/ActiveDirectory)
771 */
772
Ed Tanous4f48d5f2021-06-21 08:27:45 -0700773inline void
774 handleBaseDNPatch(const std::vector<std::string>& baseDNList,
775 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
776 const std::string& ldapServerElementName,
777 const std::string& ldapConfigObject)
Ed Tanous6c51eab2021-06-03 12:30:29 -0700778{
779 crow::connections::systemBus->async_method_call(
780 [asyncResp, baseDNList,
781 ldapServerElementName](const boost::system::error_code ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700782 if (ec)
783 {
784 BMCWEB_LOG_DEBUG << "Error Occurred in Updating the base DN";
785 messages::internalError(asyncResp->res);
786 return;
787 }
788 auto& serverTypeJson = asyncResp->res.jsonValue[ldapServerElementName];
789 auto& searchSettingsJson =
790 serverTypeJson["LDAPService"]["SearchSettings"];
791 std::vector<std::string> modifiedBaseDNList = {baseDNList.front()};
792 searchSettingsJson["BaseDistinguishedNames"] = modifiedBaseDNList;
793 if (baseDNList.size() > 1)
794 {
795 messages::propertyValueModified(
796 asyncResp->res, "BaseDistinguishedNames", baseDNList.front());
797 }
798 BMCWEB_LOG_DEBUG << "Updated the base DN";
Ed Tanous6c51eab2021-06-03 12:30:29 -0700799 },
800 ldapDbusService, ldapConfigObject, propertyInterface, "Set",
801 ldapConfigInterface, "LDAPBaseDN",
Ed Tanous168e20c2021-12-13 14:39:53 -0800802 dbus::utility::DbusVariantType(baseDNList.front()));
Ed Tanous6c51eab2021-06-03 12:30:29 -0700803}
804/**
805 * @brief updates the LDAP user name attribute and updates the
806 json response with the new value.
807 * @param userNameAttribute attribute to be updated.
808 * @param asyncResp pointer to the JSON response
809 * @param ldapServerElementName Type of LDAP
810 server(openLDAP/ActiveDirectory)
811 */
812
Ed Tanous4f48d5f2021-06-21 08:27:45 -0700813inline void
814 handleUserNameAttrPatch(const std::string& userNameAttribute,
815 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
816 const std::string& ldapServerElementName,
817 const std::string& ldapConfigObject)
Ed Tanous6c51eab2021-06-03 12:30:29 -0700818{
819 crow::connections::systemBus->async_method_call(
820 [asyncResp, userNameAttribute,
821 ldapServerElementName](const boost::system::error_code ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700822 if (ec)
823 {
824 BMCWEB_LOG_DEBUG << "Error Occurred in Updating the "
825 "username attribute";
826 messages::internalError(asyncResp->res);
827 return;
828 }
829 auto& serverTypeJson = asyncResp->res.jsonValue[ldapServerElementName];
830 auto& searchSettingsJson =
831 serverTypeJson["LDAPService"]["SearchSettings"];
832 searchSettingsJson["UsernameAttribute"] = userNameAttribute;
833 BMCWEB_LOG_DEBUG << "Updated the user name attr.";
Ed Tanous6c51eab2021-06-03 12:30:29 -0700834 },
835 ldapDbusService, ldapConfigObject, propertyInterface, "Set",
836 ldapConfigInterface, "UserNameAttribute",
Ed Tanous168e20c2021-12-13 14:39:53 -0800837 dbus::utility::DbusVariantType(userNameAttribute));
Ed Tanous6c51eab2021-06-03 12:30:29 -0700838}
839/**
840 * @brief updates the LDAP group attribute and updates the
841 json response with the new value.
842 * @param groupsAttribute attribute to be updated.
843 * @param asyncResp pointer to the JSON response
844 * @param ldapServerElementName Type of LDAP
845 server(openLDAP/ActiveDirectory)
846 */
847
Ed Tanous4f48d5f2021-06-21 08:27:45 -0700848inline void handleGroupNameAttrPatch(
Ed Tanous6c51eab2021-06-03 12:30:29 -0700849 const std::string& groupsAttribute,
850 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
851 const std::string& ldapServerElementName,
852 const std::string& ldapConfigObject)
853{
854 crow::connections::systemBus->async_method_call(
855 [asyncResp, groupsAttribute,
856 ldapServerElementName](const boost::system::error_code ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700857 if (ec)
858 {
859 BMCWEB_LOG_DEBUG << "Error Occurred in Updating the "
860 "groupname attribute";
861 messages::internalError(asyncResp->res);
862 return;
863 }
864 auto& serverTypeJson = asyncResp->res.jsonValue[ldapServerElementName];
865 auto& searchSettingsJson =
866 serverTypeJson["LDAPService"]["SearchSettings"];
867 searchSettingsJson["GroupsAttribute"] = groupsAttribute;
868 BMCWEB_LOG_DEBUG << "Updated the groupname attr";
Ed Tanous6c51eab2021-06-03 12:30:29 -0700869 },
870 ldapDbusService, ldapConfigObject, propertyInterface, "Set",
871 ldapConfigInterface, "GroupNameAttribute",
Ed Tanous168e20c2021-12-13 14:39:53 -0800872 dbus::utility::DbusVariantType(groupsAttribute));
Ed Tanous6c51eab2021-06-03 12:30:29 -0700873}
874/**
875 * @brief updates the LDAP service enable and updates the
876 json response with the new value.
877 * @param input JSON data.
878 * @param asyncResp pointer to the JSON response
879 * @param ldapServerElementName Type of LDAP
880 server(openLDAP/ActiveDirectory)
881 */
882
Ed Tanous4f48d5f2021-06-21 08:27:45 -0700883inline void handleServiceEnablePatch(
Ed Tanous6c51eab2021-06-03 12:30:29 -0700884 bool serviceEnabled, const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
885 const std::string& ldapServerElementName,
886 const std::string& ldapConfigObject)
887{
888 crow::connections::systemBus->async_method_call(
889 [asyncResp, serviceEnabled,
890 ldapServerElementName](const boost::system::error_code ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700891 if (ec)
892 {
893 BMCWEB_LOG_DEBUG << "Error Occurred in Updating the service enable";
894 messages::internalError(asyncResp->res);
895 return;
896 }
897 asyncResp->res.jsonValue[ldapServerElementName]["ServiceEnabled"] =
898 serviceEnabled;
899 BMCWEB_LOG_DEBUG << "Updated Service enable = " << serviceEnabled;
Ed Tanous6c51eab2021-06-03 12:30:29 -0700900 },
901 ldapDbusService, ldapConfigObject, propertyInterface, "Set",
Ed Tanous168e20c2021-12-13 14:39:53 -0800902 ldapEnableInterface, "Enabled",
903 dbus::utility::DbusVariantType(serviceEnabled));
Ed Tanous6c51eab2021-06-03 12:30:29 -0700904}
905
Ed Tanous4f48d5f2021-06-21 08:27:45 -0700906inline void
907 handleAuthMethodsPatch(nlohmann::json& input,
908 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Ed Tanous6c51eab2021-06-03 12:30:29 -0700909{
910 std::optional<bool> basicAuth;
911 std::optional<bool> cookie;
912 std::optional<bool> sessionToken;
913 std::optional<bool> xToken;
914 std::optional<bool> tls;
915
916 if (!json_util::readJson(input, asyncResp->res, "BasicAuth", basicAuth,
917 "Cookie", cookie, "SessionToken", sessionToken,
918 "XToken", xToken, "TLS", tls))
Ratan Gupta8a07d282019-03-16 08:33:47 +0530919 {
Ed Tanous6c51eab2021-06-03 12:30:29 -0700920 BMCWEB_LOG_ERROR << "Cannot read values from AuthMethod tag";
921 return;
922 }
923
924 // Make a copy of methods configuration
925 persistent_data::AuthConfigMethods authMethodsConfig =
926 persistent_data::SessionStore::getInstance().getAuthMethodsConfig();
927
928 if (basicAuth)
929 {
930#ifndef BMCWEB_ENABLE_BASIC_AUTHENTICATION
931 messages::actionNotSupported(
George Liu0fda0f12021-11-16 10:06:17 +0800932 asyncResp->res,
933 "Setting BasicAuth when basic-auth feature is disabled");
Ed Tanous6c51eab2021-06-03 12:30:29 -0700934 return;
935#endif
936 authMethodsConfig.basic = *basicAuth;
937 }
938
939 if (cookie)
940 {
941#ifndef BMCWEB_ENABLE_COOKIE_AUTHENTICATION
George Liu0fda0f12021-11-16 10:06:17 +0800942 messages::actionNotSupported(
943 asyncResp->res,
944 "Setting Cookie when cookie-auth feature is disabled");
Ed Tanous6c51eab2021-06-03 12:30:29 -0700945 return;
946#endif
947 authMethodsConfig.cookie = *cookie;
948 }
949
950 if (sessionToken)
951 {
952#ifndef BMCWEB_ENABLE_SESSION_AUTHENTICATION
953 messages::actionNotSupported(
George Liu0fda0f12021-11-16 10:06:17 +0800954 asyncResp->res,
955 "Setting SessionToken when session-auth feature is disabled");
Ed Tanous6c51eab2021-06-03 12:30:29 -0700956 return;
957#endif
958 authMethodsConfig.sessionToken = *sessionToken;
959 }
960
961 if (xToken)
962 {
963#ifndef BMCWEB_ENABLE_XTOKEN_AUTHENTICATION
George Liu0fda0f12021-11-16 10:06:17 +0800964 messages::actionNotSupported(
965 asyncResp->res,
966 "Setting XToken when xtoken-auth feature is disabled");
Ed Tanous6c51eab2021-06-03 12:30:29 -0700967 return;
968#endif
969 authMethodsConfig.xtoken = *xToken;
970 }
971
972 if (tls)
973 {
974#ifndef BMCWEB_ENABLE_MUTUAL_TLS_AUTHENTICATION
George Liu0fda0f12021-11-16 10:06:17 +0800975 messages::actionNotSupported(
976 asyncResp->res,
977 "Setting TLS when mutual-tls-auth feature is disabled");
Ed Tanous6c51eab2021-06-03 12:30:29 -0700978 return;
979#endif
980 authMethodsConfig.tls = *tls;
981 }
982
983 if (!authMethodsConfig.basic && !authMethodsConfig.cookie &&
984 !authMethodsConfig.sessionToken && !authMethodsConfig.xtoken &&
985 !authMethodsConfig.tls)
986 {
987 // Do not allow user to disable everything
988 messages::actionNotSupported(asyncResp->res,
989 "of disabling all available methods");
990 return;
991 }
992
993 persistent_data::SessionStore::getInstance().updateAuthMethodsConfig(
994 authMethodsConfig);
995 // Save configuration immediately
996 persistent_data::getConfig().writeData();
997
998 messages::success(asyncResp->res);
999}
1000
1001/**
1002 * @brief Get the required values from the given JSON, validates the
1003 * value and create the LDAP config object.
1004 * @param input JSON data
1005 * @param asyncResp pointer to the JSON response
1006 * @param serverType Type of LDAP server(openLDAP/ActiveDirectory)
1007 */
1008
1009inline void handleLDAPPatch(nlohmann::json& input,
1010 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1011 const std::string& serverType)
1012{
1013 std::string dbusObjectPath;
1014 if (serverType == "ActiveDirectory")
1015 {
1016 dbusObjectPath = adConfigObject;
1017 }
1018 else if (serverType == "LDAP")
1019 {
1020 dbusObjectPath = ldapConfigObjectName;
1021 }
1022 else
1023 {
1024 return;
1025 }
1026
1027 std::optional<nlohmann::json> authentication;
1028 std::optional<nlohmann::json> ldapService;
1029 std::optional<std::vector<std::string>> serviceAddressList;
1030 std::optional<bool> serviceEnabled;
1031 std::optional<std::vector<std::string>> baseDNList;
1032 std::optional<std::string> userNameAttribute;
1033 std::optional<std::string> groupsAttribute;
1034 std::optional<std::string> userName;
1035 std::optional<std::string> password;
1036 std::optional<std::vector<nlohmann::json>> remoteRoleMapData;
1037
1038 if (!json_util::readJson(input, asyncResp->res, "Authentication",
1039 authentication, "LDAPService", ldapService,
1040 "ServiceAddresses", serviceAddressList,
1041 "ServiceEnabled", serviceEnabled,
1042 "RemoteRoleMapping", remoteRoleMapData))
1043 {
1044 return;
1045 }
1046
1047 if (authentication)
1048 {
1049 parseLDAPAuthenticationJson(*authentication, asyncResp, userName,
1050 password);
1051 }
1052 if (ldapService)
1053 {
1054 parseLDAPServiceJson(*ldapService, asyncResp, baseDNList,
1055 userNameAttribute, groupsAttribute);
1056 }
1057 if (serviceAddressList)
1058 {
Ed Tanous26f69762022-01-25 09:49:11 -08001059 if (serviceAddressList->empty())
Ratan Guptaeb2bbe52019-04-22 14:27:01 +05301060 {
Ed Tanous6c51eab2021-06-03 12:30:29 -07001061 messages::propertyValueNotInList(asyncResp->res, "[]",
1062 "ServiceAddress");
Ed Tanouscb13a392020-07-25 19:02:03 +00001063 return;
1064 }
Ed Tanous6c51eab2021-06-03 12:30:29 -07001065 }
1066 if (baseDNList)
1067 {
Ed Tanous26f69762022-01-25 09:49:11 -08001068 if (baseDNList->empty())
Ratan Gupta8a07d282019-03-16 08:33:47 +05301069 {
Ed Tanous6c51eab2021-06-03 12:30:29 -07001070 messages::propertyValueNotInList(asyncResp->res, "[]",
1071 "BaseDistinguishedNames");
Ratan Gupta8a07d282019-03-16 08:33:47 +05301072 return;
1073 }
Ed Tanous6c51eab2021-06-03 12:30:29 -07001074 }
Ratan Gupta8a07d282019-03-16 08:33:47 +05301075
Ed Tanous6c51eab2021-06-03 12:30:29 -07001076 // nothing to update, then return
1077 if (!userName && !password && !serviceAddressList && !baseDNList &&
1078 !userNameAttribute && !groupsAttribute && !serviceEnabled &&
1079 !remoteRoleMapData)
1080 {
1081 return;
1082 }
1083
1084 // Get the existing resource first then keep modifying
1085 // whenever any property gets updated.
Ed Tanous002d39b2022-05-31 08:59:27 -07001086 getLDAPConfigData(
1087 serverType,
1088 [asyncResp, userName, password, baseDNList, userNameAttribute,
1089 groupsAttribute, serviceAddressList, serviceEnabled, dbusObjectPath,
1090 remoteRoleMapData](bool success, const LDAPConfigData& confData,
1091 const std::string& serverT) {
Ed Tanous6c51eab2021-06-03 12:30:29 -07001092 if (!success)
Ratan Gupta8a07d282019-03-16 08:33:47 +05301093 {
Ed Tanous6c51eab2021-06-03 12:30:29 -07001094 messages::internalError(asyncResp->res);
1095 return;
Ratan Gupta8a07d282019-03-16 08:33:47 +05301096 }
Ed Tanous6c51eab2021-06-03 12:30:29 -07001097 parseLDAPConfigData(asyncResp->res.jsonValue, confData, serverT);
1098 if (confData.serviceEnabled)
Ratan Gupta8a07d282019-03-16 08:33:47 +05301099 {
Ed Tanous6c51eab2021-06-03 12:30:29 -07001100 // Disable the service first and update the rest of
1101 // the properties.
1102 handleServiceEnablePatch(false, asyncResp, serverT, dbusObjectPath);
Ratan Gupta8a07d282019-03-16 08:33:47 +05301103 }
Ed Tanous6c51eab2021-06-03 12:30:29 -07001104
Ratan Gupta8a07d282019-03-16 08:33:47 +05301105 if (serviceAddressList)
1106 {
Ed Tanous6c51eab2021-06-03 12:30:29 -07001107 handleServiceAddressPatch(*serviceAddressList, asyncResp, serverT,
1108 dbusObjectPath);
Ratan Gupta8a07d282019-03-16 08:33:47 +05301109 }
Ed Tanous6c51eab2021-06-03 12:30:29 -07001110 if (userName)
1111 {
1112 handleUserNamePatch(*userName, asyncResp, serverT, dbusObjectPath);
1113 }
1114 if (password)
1115 {
1116 handlePasswordPatch(*password, asyncResp, serverT, dbusObjectPath);
1117 }
1118
Ratan Gupta8a07d282019-03-16 08:33:47 +05301119 if (baseDNList)
1120 {
Ed Tanous6c51eab2021-06-03 12:30:29 -07001121 handleBaseDNPatch(*baseDNList, asyncResp, serverT, dbusObjectPath);
1122 }
1123 if (userNameAttribute)
1124 {
1125 handleUserNameAttrPatch(*userNameAttribute, asyncResp, serverT,
1126 dbusObjectPath);
1127 }
1128 if (groupsAttribute)
1129 {
1130 handleGroupNameAttrPatch(*groupsAttribute, asyncResp, serverT,
1131 dbusObjectPath);
1132 }
1133 if (serviceEnabled)
1134 {
1135 // if user has given the value as true then enable
1136 // the service. if user has given false then no-op
1137 // as service is already stopped.
1138 if (*serviceEnabled)
Ratan Gupta8a07d282019-03-16 08:33:47 +05301139 {
Ed Tanous6c51eab2021-06-03 12:30:29 -07001140 handleServiceEnablePatch(*serviceEnabled, asyncResp, serverT,
1141 dbusObjectPath);
Ratan Gupta8a07d282019-03-16 08:33:47 +05301142 }
1143 }
jayaprakash Mutyala96200602020-04-08 11:09:10 +00001144 else
1145 {
Ed Tanous6c51eab2021-06-03 12:30:29 -07001146 // if user has not given the service enabled value
1147 // then revert it to the same state as it was
1148 // before.
1149 handleServiceEnablePatch(confData.serviceEnabled, asyncResp,
1150 serverT, dbusObjectPath);
jayaprakash Mutyala96200602020-04-08 11:09:10 +00001151 }
Ed Tanous04ae99e2018-09-20 15:54:36 -07001152
Ed Tanous6c51eab2021-06-03 12:30:29 -07001153 if (remoteRoleMapData)
1154 {
1155 handleRoleMapPatch(asyncResp, confData.groupRoleList, serverT,
1156 *remoteRoleMapData);
1157 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001158 });
Ed Tanous6c51eab2021-06-03 12:30:29 -07001159}
1160
1161inline void updateUserProperties(std::shared_ptr<bmcweb::AsyncResp> asyncResp,
1162 const std::string& username,
1163 std::optional<std::string> password,
1164 std::optional<bool> enabled,
1165 std::optional<std::string> roleId,
1166 std::optional<bool> locked)
1167{
P Dheeraj Srujan Kumarb477fd42021-12-16 07:17:51 +05301168 sdbusplus::message::object_path tempObjPath(rootUserDbusPath);
1169 tempObjPath /= username;
1170 std::string dbusObjectPath(tempObjPath);
Ed Tanous6c51eab2021-06-03 12:30:29 -07001171
1172 dbus::utility::checkDbusPathExists(
1173 dbusObjectPath,
Ed Tanous11063332021-09-24 11:55:44 -07001174 [dbusObjectPath, username, password(std::move(password)),
1175 roleId(std::move(roleId)), enabled, locked,
1176 asyncResp{std::move(asyncResp)}](int rc) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001177 if (rc <= 0)
1178 {
Jiaqing Zhaod8a5d5d2022-08-05 16:21:51 +08001179 messages::resourceNotFound(asyncResp->res, "ManagerAccount",
Ed Tanous002d39b2022-05-31 08:59:27 -07001180 username);
1181 return;
1182 }
1183
1184 if (password)
1185 {
1186 int retval = pamUpdatePassword(username, *password);
1187
1188 if (retval == PAM_USER_UNKNOWN)
Ed Tanous6c51eab2021-06-03 12:30:29 -07001189 {
Jiaqing Zhaod8a5d5d2022-08-05 16:21:51 +08001190 messages::resourceNotFound(asyncResp->res, "ManagerAccount",
1191 username);
Ed Tanous002d39b2022-05-31 08:59:27 -07001192 }
1193 else if (retval == PAM_AUTHTOK_ERR)
1194 {
1195 // If password is invalid
1196 messages::propertyValueFormatError(asyncResp->res, *password,
1197 "Password");
1198 BMCWEB_LOG_ERROR << "pamUpdatePassword Failed";
1199 }
1200 else if (retval != PAM_SUCCESS)
1201 {
1202 messages::internalError(asyncResp->res);
Ed Tanous6c51eab2021-06-03 12:30:29 -07001203 return;
1204 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001205 else
Ed Tanous6c51eab2021-06-03 12:30:29 -07001206 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001207 messages::success(asyncResp->res);
1208 }
1209 }
Ed Tanous6c51eab2021-06-03 12:30:29 -07001210
Ed Tanous002d39b2022-05-31 08:59:27 -07001211 if (enabled)
1212 {
1213 crow::connections::systemBus->async_method_call(
1214 [asyncResp](const boost::system::error_code ec) {
1215 if (ec)
Ed Tanous04ae99e2018-09-20 15:54:36 -07001216 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001217 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
Ayushi Smriti599c71d2019-08-23 17:43:18 +00001218 messages::internalError(asyncResp->res);
Ed Tanous04ae99e2018-09-20 15:54:36 -07001219 return;
1220 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001221 messages::success(asyncResp->res);
1222 return;
1223 },
1224 "xyz.openbmc_project.User.Manager", dbusObjectPath,
1225 "org.freedesktop.DBus.Properties", "Set",
1226 "xyz.openbmc_project.User.Attributes", "UserEnabled",
1227 dbus::utility::DbusVariantType{*enabled});
1228 }
1229
1230 if (roleId)
1231 {
1232 std::string priv = getPrivilegeFromRoleId(*roleId);
1233 if (priv.empty())
1234 {
1235 messages::propertyValueNotInList(asyncResp->res, *roleId,
1236 "RoleId");
1237 return;
1238 }
Ed Tanous04ae99e2018-09-20 15:54:36 -07001239
Ed Tanous002d39b2022-05-31 08:59:27 -07001240 crow::connections::systemBus->async_method_call(
1241 [asyncResp](const boost::system::error_code ec) {
1242 if (ec)
Ed Tanous04ae99e2018-09-20 15:54:36 -07001243 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001244 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
1245 messages::internalError(asyncResp->res);
Ed Tanous6c51eab2021-06-03 12:30:29 -07001246 return;
1247 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001248 messages::success(asyncResp->res);
1249 },
1250 "xyz.openbmc_project.User.Manager", dbusObjectPath,
1251 "org.freedesktop.DBus.Properties", "Set",
1252 "xyz.openbmc_project.User.Attributes", "UserPrivilege",
1253 dbus::utility::DbusVariantType{priv});
1254 }
Ed Tanous6c51eab2021-06-03 12:30:29 -07001255
Ed Tanous002d39b2022-05-31 08:59:27 -07001256 if (locked)
1257 {
1258 // admin can unlock the account which is locked by
1259 // successive authentication failures but admin should
1260 // not be allowed to lock an account.
1261 if (*locked)
1262 {
1263 messages::propertyValueNotInList(asyncResp->res, "true",
1264 "Locked");
1265 return;
Ed Tanous6c51eab2021-06-03 12:30:29 -07001266 }
1267
Ed Tanous002d39b2022-05-31 08:59:27 -07001268 crow::connections::systemBus->async_method_call(
1269 [asyncResp](const boost::system::error_code ec) {
1270 if (ec)
Ed Tanous6c51eab2021-06-03 12:30:29 -07001271 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001272 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
1273 messages::internalError(asyncResp->res);
Ed Tanous04ae99e2018-09-20 15:54:36 -07001274 return;
1275 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001276 messages::success(asyncResp->res);
1277 return;
1278 },
1279 "xyz.openbmc_project.User.Manager", dbusObjectPath,
1280 "org.freedesktop.DBus.Properties", "Set",
1281 "xyz.openbmc_project.User.Attributes",
1282 "UserLockedForFailedAttempt",
1283 dbus::utility::DbusVariantType{*locked});
1284 }
Ed Tanous6c51eab2021-06-03 12:30:29 -07001285 });
1286}
Ed Tanousb9b2e0b2018-09-13 13:47:50 -07001287
Ed Tanous4c7d4d32022-07-07 15:29:35 -07001288inline void handleAccountServiceHead(
1289 App& app, const crow::Request& req,
1290 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Ed Tanous1ef4c342022-05-12 16:12:36 -07001291{
Ed Tanous4c7d4d32022-07-07 15:29:35 -07001292
Ed Tanous1ef4c342022-05-12 16:12:36 -07001293 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1294 {
1295 return;
1296 }
Ed Tanous4c7d4d32022-07-07 15:29:35 -07001297 asyncResp->res.addHeader(
1298 boost::beast::http::field::link,
1299 "</redfish/v1/JsonSchemas/AccountService/AccountService.json>; rel=describedby");
1300}
1301
1302inline void
1303 handleAccountServiceGet(App& app, const crow::Request& req,
1304 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1305{
1306 handleAccountServiceHead(app, req, asyncResp);
Ed Tanous1ef4c342022-05-12 16:12:36 -07001307 const persistent_data::AuthConfigMethods& authMethodsConfig =
1308 persistent_data::SessionStore::getInstance().getAuthMethodsConfig();
1309
1310 nlohmann::json& json = asyncResp->res.jsonValue;
1311 json["@odata.id"] = "/redfish/v1/AccountService";
1312 json["@odata.type"] = "#AccountService."
1313 "v1_10_0.AccountService";
1314 json["Id"] = "AccountService";
1315 json["Name"] = "Account Service";
1316 json["Description"] = "Account Service";
1317 json["ServiceEnabled"] = true;
1318 json["MaxPasswordLength"] = 20;
1319 json["Accounts"]["@odata.id"] = "/redfish/v1/AccountService/Accounts";
1320 json["Roles"]["@odata.id"] = "/redfish/v1/AccountService/Roles";
1321 json["Oem"]["OpenBMC"]["@odata.type"] =
1322 "#OemAccountService.v1_0_0.AccountService";
1323 json["Oem"]["OpenBMC"]["@odata.id"] =
1324 "/redfish/v1/AccountService#/Oem/OpenBMC";
1325 json["Oem"]["OpenBMC"]["AuthMethods"]["BasicAuth"] =
1326 authMethodsConfig.basic;
1327 json["Oem"]["OpenBMC"]["AuthMethods"]["SessionToken"] =
1328 authMethodsConfig.sessionToken;
1329 json["Oem"]["OpenBMC"]["AuthMethods"]["XToken"] = authMethodsConfig.xtoken;
1330 json["Oem"]["OpenBMC"]["AuthMethods"]["Cookie"] = authMethodsConfig.cookie;
1331 json["Oem"]["OpenBMC"]["AuthMethods"]["TLS"] = authMethodsConfig.tls;
1332
1333 // /redfish/v1/AccountService/LDAP/Certificates is something only
1334 // ConfigureManager can access then only display when the user has
1335 // permissions ConfigureManager
1336 Privileges effectiveUserPrivileges =
1337 redfish::getUserPrivileges(req.userRole);
1338
1339 if (isOperationAllowedWithPrivileges({{"ConfigureManager"}},
1340 effectiveUserPrivileges))
1341 {
1342 asyncResp->res.jsonValue["LDAP"]["Certificates"]["@odata.id"] =
1343 "/redfish/v1/AccountService/LDAP/Certificates";
1344 }
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001345 sdbusplus::asio::getAllProperties(
1346 *crow::connections::systemBus, "xyz.openbmc_project.User.Manager",
1347 "/xyz/openbmc_project/user", "xyz.openbmc_project.User.AccountPolicy",
Ed Tanous1ef4c342022-05-12 16:12:36 -07001348 [asyncResp](const boost::system::error_code ec,
1349 const dbus::utility::DBusPropertiesMap& propertiesList) {
1350 if (ec)
1351 {
1352 messages::internalError(asyncResp->res);
1353 return;
1354 }
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001355
Ed Tanous1ef4c342022-05-12 16:12:36 -07001356 BMCWEB_LOG_DEBUG << "Got " << propertiesList.size()
1357 << "properties for AccountService";
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001358
1359 const uint8_t* minPasswordLength = nullptr;
1360 const uint32_t* accountUnlockTimeout = nullptr;
1361 const uint16_t* maxLoginAttemptBeforeLockout = nullptr;
1362
1363 const bool success = sdbusplus::unpackPropertiesNoThrow(
1364 dbus_utils::UnpackErrorPrinter(), propertiesList,
1365 "MinPasswordLength", minPasswordLength, "AccountUnlockTimeout",
1366 accountUnlockTimeout, "MaxLoginAttemptBeforeLockout",
1367 maxLoginAttemptBeforeLockout);
1368
1369 if (!success)
Ed Tanous1ef4c342022-05-12 16:12:36 -07001370 {
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001371 messages::internalError(asyncResp->res);
1372 return;
Ed Tanous1ef4c342022-05-12 16:12:36 -07001373 }
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001374
1375 if (minPasswordLength != nullptr)
1376 {
1377 asyncResp->res.jsonValue["MinPasswordLength"] = *minPasswordLength;
1378 }
1379
1380 if (accountUnlockTimeout != nullptr)
1381 {
1382 asyncResp->res.jsonValue["AccountLockoutDuration"] =
1383 *accountUnlockTimeout;
1384 }
1385
1386 if (maxLoginAttemptBeforeLockout != nullptr)
1387 {
1388 asyncResp->res.jsonValue["AccountLockoutThreshold"] =
1389 *maxLoginAttemptBeforeLockout;
1390 }
1391 });
Ed Tanous1ef4c342022-05-12 16:12:36 -07001392
Ed Tanous02cad962022-06-30 16:50:15 -07001393 auto callback = [asyncResp](bool success, const LDAPConfigData& confData,
Ed Tanous1ef4c342022-05-12 16:12:36 -07001394 const std::string& ldapType) {
1395 if (!success)
1396 {
1397 return;
1398 }
1399 parseLDAPConfigData(asyncResp->res.jsonValue, confData, ldapType);
1400 };
1401
1402 getLDAPConfigData("LDAP", callback);
1403 getLDAPConfigData("ActiveDirectory", callback);
1404}
1405
1406inline void handleAccountServicePatch(
1407 App& app, const crow::Request& req,
1408 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1409{
1410 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1411 {
1412 return;
1413 }
1414 std::optional<uint32_t> unlockTimeout;
1415 std::optional<uint16_t> lockoutThreshold;
1416 std::optional<uint8_t> minPasswordLength;
1417 std::optional<uint16_t> maxPasswordLength;
1418 std::optional<nlohmann::json> ldapObject;
1419 std::optional<nlohmann::json> activeDirectoryObject;
1420 std::optional<nlohmann::json> oemObject;
1421
1422 if (!json_util::readJsonPatch(
1423 req, asyncResp->res, "AccountLockoutDuration", unlockTimeout,
1424 "AccountLockoutThreshold", lockoutThreshold, "MaxPasswordLength",
1425 maxPasswordLength, "MinPasswordLength", minPasswordLength, "LDAP",
1426 ldapObject, "ActiveDirectory", activeDirectoryObject, "Oem",
1427 oemObject))
1428 {
1429 return;
1430 }
1431
1432 if (minPasswordLength)
1433 {
1434 crow::connections::systemBus->async_method_call(
1435 [asyncResp](const boost::system::error_code ec) {
1436 if (ec)
1437 {
1438 messages::internalError(asyncResp->res);
1439 return;
1440 }
1441 messages::success(asyncResp->res);
1442 },
1443 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
1444 "org.freedesktop.DBus.Properties", "Set",
1445 "xyz.openbmc_project.User.AccountPolicy", "MinPasswordLength",
1446 dbus::utility::DbusVariantType(*minPasswordLength));
1447 }
1448
1449 if (maxPasswordLength)
1450 {
1451 messages::propertyNotWritable(asyncResp->res, "MaxPasswordLength");
1452 }
1453
1454 if (ldapObject)
1455 {
1456 handleLDAPPatch(*ldapObject, asyncResp, "LDAP");
1457 }
1458
1459 if (std::optional<nlohmann::json> oemOpenBMCObject;
1460 oemObject && json_util::readJson(*oemObject, asyncResp->res, "OpenBMC",
1461 oemOpenBMCObject))
1462 {
1463 if (std::optional<nlohmann::json> authMethodsObject;
1464 oemOpenBMCObject &&
1465 json_util::readJson(*oemOpenBMCObject, asyncResp->res,
1466 "AuthMethods", authMethodsObject))
1467 {
1468 if (authMethodsObject)
1469 {
1470 handleAuthMethodsPatch(*authMethodsObject, asyncResp);
1471 }
1472 }
1473 }
1474
1475 if (activeDirectoryObject)
1476 {
1477 handleLDAPPatch(*activeDirectoryObject, asyncResp, "ActiveDirectory");
1478 }
1479
1480 if (unlockTimeout)
1481 {
1482 crow::connections::systemBus->async_method_call(
1483 [asyncResp](const boost::system::error_code ec) {
1484 if (ec)
1485 {
1486 messages::internalError(asyncResp->res);
1487 return;
1488 }
1489 messages::success(asyncResp->res);
1490 },
1491 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
1492 "org.freedesktop.DBus.Properties", "Set",
1493 "xyz.openbmc_project.User.AccountPolicy", "AccountUnlockTimeout",
1494 dbus::utility::DbusVariantType(*unlockTimeout));
1495 }
1496 if (lockoutThreshold)
1497 {
1498 crow::connections::systemBus->async_method_call(
1499 [asyncResp](const boost::system::error_code ec) {
1500 if (ec)
1501 {
1502 messages::internalError(asyncResp->res);
1503 return;
1504 }
1505 messages::success(asyncResp->res);
1506 },
1507 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
1508 "org.freedesktop.DBus.Properties", "Set",
1509 "xyz.openbmc_project.User.AccountPolicy",
1510 "MaxLoginAttemptBeforeLockout",
1511 dbus::utility::DbusVariantType(*lockoutThreshold));
1512 }
1513}
1514
Ed Tanous4c7d4d32022-07-07 15:29:35 -07001515inline void handleAccountCollectionHead(
Ed Tanous1ef4c342022-05-12 16:12:36 -07001516 App& app, const crow::Request& req,
1517 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1518{
Ed Tanous4c7d4d32022-07-07 15:29:35 -07001519
Ed Tanous1ef4c342022-05-12 16:12:36 -07001520 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1521 {
1522 return;
1523 }
Ed Tanous4c7d4d32022-07-07 15:29:35 -07001524 asyncResp->res.addHeader(
1525 boost::beast::http::field::link,
1526 "</redfish/v1/JsonSchemas/ManagerAccountCollection.json>; rel=describedby");
1527}
1528
1529inline void handleAccountCollectionGet(
1530 App& app, const crow::Request& req,
1531 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1532{
1533 handleAccountCollectionHead(app, req, asyncResp);
Ed Tanous1ef4c342022-05-12 16:12:36 -07001534
1535 asyncResp->res.jsonValue["@odata.id"] =
1536 "/redfish/v1/AccountService/Accounts";
1537 asyncResp->res.jsonValue["@odata.type"] = "#ManagerAccountCollection."
1538 "ManagerAccountCollection";
1539 asyncResp->res.jsonValue["Name"] = "Accounts Collection";
1540 asyncResp->res.jsonValue["Description"] = "BMC User Accounts";
1541
1542 Privileges effectiveUserPrivileges =
1543 redfish::getUserPrivileges(req.userRole);
1544
1545 std::string thisUser;
1546 if (req.session)
1547 {
1548 thisUser = req.session->username;
1549 }
1550 crow::connections::systemBus->async_method_call(
1551 [asyncResp, thisUser, effectiveUserPrivileges](
1552 const boost::system::error_code ec,
1553 const dbus::utility::ManagedObjectType& users) {
1554 if (ec)
1555 {
1556 messages::internalError(asyncResp->res);
1557 return;
1558 }
1559
1560 bool userCanSeeAllAccounts =
1561 effectiveUserPrivileges.isSupersetOf({"ConfigureUsers"});
1562
1563 bool userCanSeeSelf =
1564 effectiveUserPrivileges.isSupersetOf({"ConfigureSelf"});
1565
1566 nlohmann::json& memberArray = asyncResp->res.jsonValue["Members"];
1567 memberArray = nlohmann::json::array();
1568
1569 for (const auto& userpath : users)
1570 {
1571 std::string user = userpath.first.filename();
1572 if (user.empty())
1573 {
1574 messages::internalError(asyncResp->res);
1575 BMCWEB_LOG_ERROR << "Invalid firmware ID";
1576
1577 return;
1578 }
1579
1580 // As clarified by Redfish here:
1581 // https://redfishforum.com/thread/281/manageraccountcollection-change-allows-account-enumeration
1582 // Users without ConfigureUsers, only see their own
1583 // account. Users with ConfigureUsers, see all
1584 // accounts.
1585 if (userCanSeeAllAccounts || (thisUser == user && userCanSeeSelf))
1586 {
1587 nlohmann::json::object_t member;
1588 member["@odata.id"] =
1589 "/redfish/v1/AccountService/Accounts/" + user;
1590 memberArray.push_back(std::move(member));
1591 }
1592 }
1593 asyncResp->res.jsonValue["Members@odata.count"] = memberArray.size();
1594 },
1595 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
1596 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
1597}
1598
1599inline void handleAccountCollectionPost(
1600 App& app, const crow::Request& req,
1601 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1602{
1603 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1604 {
1605 return;
1606 }
1607 std::string username;
1608 std::string password;
1609 std::optional<std::string> roleId("User");
1610 std::optional<bool> enabled = true;
1611 if (!json_util::readJsonPatch(req, asyncResp->res, "UserName", username,
1612 "Password", password, "RoleId", roleId,
1613 "Enabled", enabled))
1614 {
1615 return;
1616 }
1617
1618 std::string priv = getPrivilegeFromRoleId(*roleId);
1619 if (priv.empty())
1620 {
1621 messages::propertyValueNotInList(asyncResp->res, *roleId, "RoleId");
1622 return;
1623 }
Asmitha Karunanithi239adf82022-03-25 02:59:03 -05001624 roleId = priv;
Ed Tanous1ef4c342022-05-12 16:12:36 -07001625
1626 // Reading AllGroups property
1627 sdbusplus::asio::getProperty<std::vector<std::string>>(
1628 *crow::connections::systemBus, "xyz.openbmc_project.User.Manager",
1629 "/xyz/openbmc_project/user", "xyz.openbmc_project.User.Manager",
1630 "AllGroups",
1631 [asyncResp, username, password{std::move(password)}, roleId,
1632 enabled](const boost::system::error_code ec,
1633 const std::vector<std::string>& allGroupsList) {
1634 if (ec)
1635 {
1636 BMCWEB_LOG_DEBUG << "ERROR with async_method_call";
1637 messages::internalError(asyncResp->res);
1638 return;
1639 }
1640
1641 if (allGroupsList.empty())
1642 {
1643 messages::internalError(asyncResp->res);
1644 return;
1645 }
1646
1647 crow::connections::systemBus->async_method_call(
1648 [asyncResp, username, password](const boost::system::error_code ec2,
Patrick Williams59d494e2022-07-22 19:26:55 -05001649 sdbusplus::message_t& m) {
Ed Tanous1ef4c342022-05-12 16:12:36 -07001650 if (ec2)
1651 {
1652 userErrorMessageHandler(m.get_error(), asyncResp, username, "");
1653 return;
1654 }
1655
1656 if (pamUpdatePassword(username, password) != PAM_SUCCESS)
1657 {
1658 // At this point we have a user that's been
1659 // created, but the password set
1660 // failed.Something is wrong, so delete the user
1661 // that we've already created
1662 sdbusplus::message::object_path tempObjPath(rootUserDbusPath);
1663 tempObjPath /= username;
1664 const std::string userPath(tempObjPath);
1665
1666 crow::connections::systemBus->async_method_call(
1667 [asyncResp, password](const boost::system::error_code ec3) {
1668 if (ec3)
1669 {
1670 messages::internalError(asyncResp->res);
1671 return;
1672 }
1673
1674 // If password is invalid
1675 messages::propertyValueFormatError(asyncResp->res, password,
1676 "Password");
1677 },
1678 "xyz.openbmc_project.User.Manager", userPath,
1679 "xyz.openbmc_project.Object.Delete", "Delete");
1680
1681 BMCWEB_LOG_ERROR << "pamUpdatePassword Failed";
1682 return;
1683 }
1684
1685 messages::created(asyncResp->res);
1686 asyncResp->res.addHeader(
1687 "Location", "/redfish/v1/AccountService/Accounts/" + username);
1688 },
1689 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
1690 "xyz.openbmc_project.User.Manager", "CreateUser", username,
1691 allGroupsList, *roleId, *enabled);
1692 });
1693}
1694
1695inline void
Ed Tanous4c7d4d32022-07-07 15:29:35 -07001696 handleAccountHead(App& app, const crow::Request& req,
1697 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1698 const std::string& /*accountName*/)
Ed Tanous1ef4c342022-05-12 16:12:36 -07001699{
Ed Tanous4c7d4d32022-07-07 15:29:35 -07001700
Ed Tanous1ef4c342022-05-12 16:12:36 -07001701 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1702 {
1703 return;
1704 }
Ed Tanous4c7d4d32022-07-07 15:29:35 -07001705 asyncResp->res.addHeader(
1706 boost::beast::http::field::link,
1707 "</redfish/v1/JsonSchemas/ManagerAccount/ManagerAccount.json>; rel=describedby");
1708}
1709inline void
1710 handleAccountGet(App& app, const crow::Request& req,
1711 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1712 const std::string& accountName)
1713{
1714 handleAccountHead(app, req, asyncResp, accountName);
Ed Tanous1ef4c342022-05-12 16:12:36 -07001715#ifdef BMCWEB_INSECURE_DISABLE_AUTHENTICATION
1716 // If authentication is disabled, there are no user accounts
Jiaqing Zhaod8a5d5d2022-08-05 16:21:51 +08001717 messages::resourceNotFound(asyncResp->res, "ManagerAccount", accountName);
Ed Tanous1ef4c342022-05-12 16:12:36 -07001718 return;
1719
1720#endif // BMCWEB_INSECURE_DISABLE_AUTHENTICATION
1721 if (req.session == nullptr)
1722 {
1723 messages::internalError(asyncResp->res);
1724 return;
1725 }
1726 if (req.session->username != accountName)
1727 {
1728 // At this point we've determined that the user is trying to
1729 // modify a user that isn't them. We need to verify that they
1730 // have permissions to modify other users, so re-run the auth
1731 // check with the same permissions, minus ConfigureSelf.
1732 Privileges effectiveUserPrivileges =
1733 redfish::getUserPrivileges(req.userRole);
1734 Privileges requiredPermissionsToChangeNonSelf = {"ConfigureUsers",
1735 "ConfigureManager"};
1736 if (!effectiveUserPrivileges.isSupersetOf(
1737 requiredPermissionsToChangeNonSelf))
1738 {
1739 BMCWEB_LOG_DEBUG << "GET Account denied access";
1740 messages::insufficientPrivilege(asyncResp->res);
1741 return;
1742 }
1743 }
1744
1745 crow::connections::systemBus->async_method_call(
1746 [asyncResp,
1747 accountName](const boost::system::error_code ec,
1748 const dbus::utility::ManagedObjectType& users) {
1749 if (ec)
1750 {
1751 messages::internalError(asyncResp->res);
1752 return;
1753 }
1754 const auto userIt = std::find_if(
1755 users.begin(), users.end(),
1756 [accountName](
1757 const std::pair<sdbusplus::message::object_path,
1758 dbus::utility::DBusInteracesMap>& user) {
1759 return accountName == user.first.filename();
1760 });
1761
1762 if (userIt == users.end())
1763 {
1764 messages::resourceNotFound(asyncResp->res, "ManagerAccount",
1765 accountName);
1766 return;
1767 }
1768
1769 asyncResp->res.jsonValue["@odata.type"] =
1770 "#ManagerAccount.v1_4_0.ManagerAccount";
1771 asyncResp->res.jsonValue["Name"] = "User Account";
1772 asyncResp->res.jsonValue["Description"] = "User Account";
1773 asyncResp->res.jsonValue["Password"] = nullptr;
Ed Tanous1ef4c342022-05-12 16:12:36 -07001774
1775 for (const auto& interface : userIt->second)
1776 {
1777 if (interface.first == "xyz.openbmc_project.User.Attributes")
1778 {
1779 for (const auto& property : interface.second)
1780 {
1781 if (property.first == "UserEnabled")
1782 {
1783 const bool* userEnabled =
1784 std::get_if<bool>(&property.second);
1785 if (userEnabled == nullptr)
1786 {
1787 BMCWEB_LOG_ERROR << "UserEnabled wasn't a bool";
1788 messages::internalError(asyncResp->res);
1789 return;
1790 }
1791 asyncResp->res.jsonValue["Enabled"] = *userEnabled;
1792 }
1793 else if (property.first == "UserLockedForFailedAttempt")
1794 {
1795 const bool* userLocked =
1796 std::get_if<bool>(&property.second);
1797 if (userLocked == nullptr)
1798 {
1799 BMCWEB_LOG_ERROR << "UserLockedForF"
1800 "ailedAttempt "
1801 "wasn't a bool";
1802 messages::internalError(asyncResp->res);
1803 return;
1804 }
1805 asyncResp->res.jsonValue["Locked"] = *userLocked;
1806 asyncResp->res
1807 .jsonValue["Locked@Redfish.AllowableValues"] = {
1808 "false"}; // can only unlock accounts
1809 }
1810 else if (property.first == "UserPrivilege")
1811 {
1812 const std::string* userPrivPtr =
1813 std::get_if<std::string>(&property.second);
1814 if (userPrivPtr == nullptr)
1815 {
1816 BMCWEB_LOG_ERROR << "UserPrivilege wasn't a "
1817 "string";
1818 messages::internalError(asyncResp->res);
1819 return;
1820 }
1821 std::string role = getRoleIdFromPrivilege(*userPrivPtr);
1822 if (role.empty())
1823 {
1824 BMCWEB_LOG_ERROR << "Invalid user role";
1825 messages::internalError(asyncResp->res);
1826 return;
1827 }
1828 asyncResp->res.jsonValue["RoleId"] = role;
1829
1830 nlohmann::json& roleEntry =
1831 asyncResp->res.jsonValue["Links"]["Role"];
1832 roleEntry["@odata.id"] =
1833 "/redfish/v1/AccountService/Roles/" + role;
1834 }
1835 else if (property.first == "UserPasswordExpired")
1836 {
1837 const bool* userPasswordExpired =
1838 std::get_if<bool>(&property.second);
1839 if (userPasswordExpired == nullptr)
1840 {
1841 BMCWEB_LOG_ERROR
1842 << "UserPasswordExpired wasn't a bool";
1843 messages::internalError(asyncResp->res);
1844 return;
1845 }
1846 asyncResp->res.jsonValue["PasswordChangeRequired"] =
1847 *userPasswordExpired;
1848 }
Abhishek Patelc7229812022-02-01 10:07:15 -06001849 else if (property.first == "UserGroups")
1850 {
1851 const std::vector<std::string>* userGroups =
1852 std::get_if<std::vector<std::string>>(
1853 &property.second);
1854 if (userGroups == nullptr)
1855 {
1856 BMCWEB_LOG_ERROR
1857 << "userGroups wasn't a string vector";
1858 messages::internalError(asyncResp->res);
1859 return;
1860 }
1861 if (!translateUserGroup(*userGroups, asyncResp->res))
1862 {
1863 BMCWEB_LOG_ERROR << "userGroups mapping failed";
1864 messages::internalError(asyncResp->res);
1865 return;
1866 }
1867 }
Ed Tanous1ef4c342022-05-12 16:12:36 -07001868 }
1869 }
1870 }
1871
1872 asyncResp->res.jsonValue["@odata.id"] =
1873 "/redfish/v1/AccountService/Accounts/" + accountName;
1874 asyncResp->res.jsonValue["Id"] = accountName;
1875 asyncResp->res.jsonValue["UserName"] = accountName;
1876 },
1877 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
1878 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
1879}
1880
1881inline void
1882 handleAccounttDelete(App& app, const crow::Request& req,
1883 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1884 const std::string& username)
1885{
1886 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1887 {
1888 return;
1889 }
1890
1891#ifdef BMCWEB_INSECURE_DISABLE_AUTHENTICATION
1892 // If authentication is disabled, there are no user accounts
Jiaqing Zhaod8a5d5d2022-08-05 16:21:51 +08001893 messages::resourceNotFound(asyncResp->res, "ManagerAccount", username);
Ed Tanous1ef4c342022-05-12 16:12:36 -07001894 return;
1895
1896#endif // BMCWEB_INSECURE_DISABLE_AUTHENTICATION
1897 sdbusplus::message::object_path tempObjPath(rootUserDbusPath);
1898 tempObjPath /= username;
1899 const std::string userPath(tempObjPath);
1900
1901 crow::connections::systemBus->async_method_call(
1902 [asyncResp, username](const boost::system::error_code ec) {
1903 if (ec)
1904 {
Jiaqing Zhaod8a5d5d2022-08-05 16:21:51 +08001905 messages::resourceNotFound(asyncResp->res, "ManagerAccount",
Ed Tanous1ef4c342022-05-12 16:12:36 -07001906 username);
1907 return;
1908 }
1909
1910 messages::accountRemoved(asyncResp->res);
1911 },
1912 "xyz.openbmc_project.User.Manager", userPath,
1913 "xyz.openbmc_project.Object.Delete", "Delete");
1914}
1915
1916inline void
1917 handleAccountPatch(App& app, const crow::Request& req,
1918 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1919 const std::string& username)
1920{
1921 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1922 {
1923 return;
1924 }
1925#ifdef BMCWEB_INSECURE_DISABLE_AUTHENTICATION
1926 // If authentication is disabled, there are no user accounts
Jiaqing Zhaod8a5d5d2022-08-05 16:21:51 +08001927 messages::resourceNotFound(asyncResp->res, "ManagerAccount", username);
Ed Tanous1ef4c342022-05-12 16:12:36 -07001928 return;
1929
1930#endif // BMCWEB_INSECURE_DISABLE_AUTHENTICATION
1931 std::optional<std::string> newUserName;
1932 std::optional<std::string> password;
1933 std::optional<bool> enabled;
1934 std::optional<std::string> roleId;
1935 std::optional<bool> locked;
1936
1937 if (req.session == nullptr)
1938 {
1939 messages::internalError(asyncResp->res);
1940 return;
1941 }
1942
1943 Privileges effectiveUserPrivileges =
1944 redfish::getUserPrivileges(req.userRole);
1945 Privileges configureUsers = {"ConfigureUsers"};
1946 bool userHasConfigureUsers =
1947 effectiveUserPrivileges.isSupersetOf(configureUsers);
1948 if (userHasConfigureUsers)
1949 {
1950 // Users with ConfigureUsers can modify for all users
1951 if (!json_util::readJsonPatch(req, asyncResp->res, "UserName",
1952 newUserName, "Password", password,
1953 "RoleId", roleId, "Enabled", enabled,
1954 "Locked", locked))
1955 {
1956 return;
1957 }
1958 }
1959 else
1960 {
1961 // ConfigureSelf accounts can only modify their own account
1962 if (username != req.session->username)
1963 {
1964 messages::insufficientPrivilege(asyncResp->res);
1965 return;
1966 }
1967
1968 // ConfigureSelf accounts can only modify their password
1969 if (!json_util::readJsonPatch(req, asyncResp->res, "Password",
1970 password))
1971 {
1972 return;
1973 }
1974 }
1975
1976 // if user name is not provided in the patch method or if it
1977 // matches the user name in the URI, then we are treating it as
1978 // updating user properties other then username. If username
1979 // provided doesn't match the URI, then we are treating this as
1980 // user rename request.
1981 if (!newUserName || (newUserName.value() == username))
1982 {
1983 updateUserProperties(asyncResp, username, password, enabled, roleId,
1984 locked);
1985 return;
1986 }
1987 crow::connections::systemBus->async_method_call(
1988 [asyncResp, username, password(std::move(password)),
1989 roleId(std::move(roleId)), enabled, newUser{std::string(*newUserName)},
Patrick Williams59d494e2022-07-22 19:26:55 -05001990 locked](const boost::system::error_code ec, sdbusplus::message_t& m) {
Ed Tanous1ef4c342022-05-12 16:12:36 -07001991 if (ec)
1992 {
1993 userErrorMessageHandler(m.get_error(), asyncResp, newUser,
1994 username);
1995 return;
1996 }
1997
1998 updateUserProperties(asyncResp, newUser, password, enabled, roleId,
1999 locked);
2000 },
2001 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
2002 "xyz.openbmc_project.User.Manager", "RenameUser", username,
2003 *newUserName);
2004}
2005
Ed Tanous6c51eab2021-06-03 12:30:29 -07002006inline void requestAccountServiceRoutes(App& app)
Ed Tanousb9b2e0b2018-09-13 13:47:50 -07002007{
Ed Tanousb9b2e0b2018-09-13 13:47:50 -07002008
Ed Tanous6c51eab2021-06-03 12:30:29 -07002009 BMCWEB_ROUTE(app, "/redfish/v1/AccountService/")
Ed Tanous4c7d4d32022-07-07 15:29:35 -07002010 .privileges(redfish::privileges::headAccountService)
2011 .methods(boost::beast::http::verb::head)(
2012 std::bind_front(handleAccountServiceHead, std::ref(app)));
2013
2014 BMCWEB_ROUTE(app, "/redfish/v1/AccountService/")
Ed Tanoused398212021-06-09 17:05:54 -07002015 .privileges(redfish::privileges::getAccountService)
Ed Tanous002d39b2022-05-31 08:59:27 -07002016 .methods(boost::beast::http::verb::get)(
Ed Tanous1ef4c342022-05-12 16:12:36 -07002017 std::bind_front(handleAccountServiceGet, std::ref(app)));
Ed Tanous6c51eab2021-06-03 12:30:29 -07002018
Ed Tanousf5ffd802021-07-19 10:55:33 -07002019 BMCWEB_ROUTE(app, "/redfish/v1/AccountService/")
Gunnar Mills1ec43ee2022-01-04 15:39:52 -06002020 .privileges(redfish::privileges::patchAccountService)
Ed Tanousf5ffd802021-07-19 10:55:33 -07002021 .methods(boost::beast::http::verb::patch)(
Ed Tanous1ef4c342022-05-12 16:12:36 -07002022 std::bind_front(handleAccountServicePatch, std::ref(app)));
Ed Tanousf5ffd802021-07-19 10:55:33 -07002023
Ed Tanous6c51eab2021-06-03 12:30:29 -07002024 BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/")
Ed Tanous4c7d4d32022-07-07 15:29:35 -07002025 .privileges(redfish::privileges::headManagerAccountCollection)
2026 .methods(boost::beast::http::verb::head)(
2027 std::bind_front(handleAccountCollectionHead, std::ref(app)));
2028
2029 BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/")
Ed Tanoused398212021-06-09 17:05:54 -07002030 .privileges(redfish::privileges::getManagerAccountCollection)
Ed Tanous6c51eab2021-06-03 12:30:29 -07002031 .methods(boost::beast::http::verb::get)(
Ed Tanous1ef4c342022-05-12 16:12:36 -07002032 std::bind_front(handleAccountCollectionGet, std::ref(app)));
Ed Tanous06e086d2018-09-19 17:19:52 -07002033
Ed Tanous6c51eab2021-06-03 12:30:29 -07002034 BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/")
Ed Tanoused398212021-06-09 17:05:54 -07002035 .privileges(redfish::privileges::postManagerAccountCollection)
Ed Tanous002d39b2022-05-31 08:59:27 -07002036 .methods(boost::beast::http::verb::post)(
Ed Tanous1ef4c342022-05-12 16:12:36 -07002037 std::bind_front(handleAccountCollectionPost, std::ref(app)));
Ed Tanous002d39b2022-05-31 08:59:27 -07002038
2039 BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/<str>/")
Ed Tanous4c7d4d32022-07-07 15:29:35 -07002040 .privileges(redfish::privileges::headManagerAccount)
2041 .methods(boost::beast::http::verb::head)(
2042 std::bind_front(handleAccountHead, std::ref(app)));
2043
2044 BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/<str>/")
Ed Tanous002d39b2022-05-31 08:59:27 -07002045 .privileges(redfish::privileges::getManagerAccount)
2046 .methods(boost::beast::http::verb::get)(
Ed Tanous1ef4c342022-05-12 16:12:36 -07002047 std::bind_front(handleAccountGet, std::ref(app)));
Ed Tanous6c51eab2021-06-03 12:30:29 -07002048
2049 BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002050 // TODO this privilege should be using the generated endpoints, but
2051 // because of the special handling of ConfigureSelf, it's not able to
2052 // yet
Ed Tanous6c51eab2021-06-03 12:30:29 -07002053 .privileges({{"ConfigureUsers"}, {"ConfigureSelf"}})
2054 .methods(boost::beast::http::verb::patch)(
Ed Tanous1ef4c342022-05-12 16:12:36 -07002055 std::bind_front(handleAccountPatch, std::ref(app)));
Ed Tanous6c51eab2021-06-03 12:30:29 -07002056
2057 BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002058 .privileges(redfish::privileges::deleteManagerAccount)
Ed Tanous6c51eab2021-06-03 12:30:29 -07002059 .methods(boost::beast::http::verb::delete_)(
Ed Tanous1ef4c342022-05-12 16:12:36 -07002060 std::bind_front(handleAccounttDelete, std::ref(app)));
Ed Tanous6c51eab2021-06-03 12:30:29 -07002061}
Lewanczyk, Dawid88d16c92018-02-02 14:51:09 +01002062
Ed Tanous1abe55e2018-09-05 08:30:59 -07002063} // namespace redfish