blob: 9f99d184ab5be47b8acf87e744f60038a16e15fb [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
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080018#include "app.hpp"
19#include "dbus_utility.hpp"
20#include "error_messages.hpp"
Ed Tanous0ec8b832022-03-14 14:56:47 -070021#include "generated/enums/account_service.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080022#include "openbmc_dbus_rest.hpp"
23#include "persistent_data.hpp"
24#include "query.hpp"
Ed Tanous0ec8b832022-03-14 14:56:47 -070025#include "registries/privilege_registry.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080026#include "utils/dbus_utils.hpp"
27#include "utils/json_utils.hpp"
Ed Tanous0ec8b832022-03-14 14:56:47 -070028
Jonathan Doman1e1e5982021-06-11 09:36:17 -070029#include <sdbusplus/asio/property.hpp>
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +020030#include <sdbusplus/unpack_properties.hpp>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050031
George Liu2b731192023-01-11 16:27:13 +080032#include <array>
Abhishek Patelc7229812022-02-01 10:07:15 -060033#include <optional>
34#include <string>
George Liu2b731192023-01-11 16:27:13 +080035#include <string_view>
Abhishek Patelc7229812022-02-01 10:07:15 -060036#include <vector>
37
Ed Tanous1abe55e2018-09-05 08:30:59 -070038namespace redfish
39{
Lewanczyk, Dawid88d16c92018-02-02 14:51:09 +010040
Ed Tanous23a21a12020-07-25 04:45:05 +000041constexpr const char* ldapConfigObjectName =
Ratan Gupta6973a582018-12-13 18:25:44 +053042 "/xyz/openbmc_project/user/ldap/openldap";
Ed Tanous2c70f802020-09-28 14:29:23 -070043constexpr const char* adConfigObject =
Ratan Guptaab828d72019-04-22 14:18:33 +053044 "/xyz/openbmc_project/user/ldap/active_directory";
45
P Dheeraj Srujan Kumarb477fd42021-12-16 07:17:51 +053046constexpr const char* rootUserDbusPath = "/xyz/openbmc_project/user/";
Ratan Gupta6973a582018-12-13 18:25:44 +053047constexpr const char* ldapRootObject = "/xyz/openbmc_project/user/ldap";
48constexpr const char* ldapDbusService = "xyz.openbmc_project.Ldap.Config";
49constexpr const char* ldapConfigInterface =
50 "xyz.openbmc_project.User.Ldap.Config";
51constexpr const char* ldapCreateInterface =
52 "xyz.openbmc_project.User.Ldap.Create";
53constexpr const char* ldapEnableInterface = "xyz.openbmc_project.Object.Enable";
Ratan Gupta06785242019-07-26 22:30:16 +053054constexpr const char* ldapPrivMapperInterface =
55 "xyz.openbmc_project.User.PrivilegeMapper";
Ratan Gupta6973a582018-12-13 18:25:44 +053056constexpr const char* dbusObjManagerIntf = "org.freedesktop.DBus.ObjectManager";
57constexpr const char* propertyInterface = "org.freedesktop.DBus.Properties";
58constexpr const char* mapperBusName = "xyz.openbmc_project.ObjectMapper";
59constexpr const char* mapperObjectPath = "/xyz/openbmc_project/object_mapper";
60constexpr const char* mapperIntf = "xyz.openbmc_project.ObjectMapper";
61
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -060062struct LDAPRoleMapData
63{
64 std::string groupName;
65 std::string privilege;
66};
67
Ratan Gupta6973a582018-12-13 18:25:44 +053068struct LDAPConfigData
69{
70 std::string uri{};
71 std::string bindDN{};
72 std::string baseDN{};
73 std::string searchScope{};
74 std::string serverType{};
75 bool serviceEnabled = false;
76 std::string userNameAttribute{};
77 std::string groupAttribute{};
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -060078 std::vector<std::pair<std::string, LDAPRoleMapData>> groupRoleList;
Ratan Gupta6973a582018-12-13 18:25:44 +053079};
80
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -060081inline std::string getRoleIdFromPrivilege(std::string_view role)
AppaRao Puli84e12cb2018-10-11 01:28:15 +053082{
83 if (role == "priv-admin")
84 {
85 return "Administrator";
86 }
Ed Tanous3174e4d2020-10-07 11:41:22 -070087 if (role == "priv-user")
AppaRao Puli84e12cb2018-10-11 01:28:15 +053088 {
AppaRao Pulic80fee52019-10-16 14:49:36 +053089 return "ReadOnly";
AppaRao Puli84e12cb2018-10-11 01:28:15 +053090 }
Ed Tanous3174e4d2020-10-07 11:41:22 -070091 if (role == "priv-operator")
AppaRao Puli84e12cb2018-10-11 01:28:15 +053092 {
93 return "Operator";
94 }
95 return "";
96}
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -060097inline std::string getPrivilegeFromRoleId(std::string_view role)
AppaRao Puli84e12cb2018-10-11 01:28:15 +053098{
99 if (role == "Administrator")
100 {
101 return "priv-admin";
102 }
Ed Tanous3174e4d2020-10-07 11:41:22 -0700103 if (role == "ReadOnly")
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530104 {
105 return "priv-user";
106 }
Ed Tanous3174e4d2020-10-07 11:41:22 -0700107 if (role == "Operator")
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530108 {
109 return "priv-operator";
110 }
111 return "";
112}
Ed Tanousb9b2e0b2018-09-13 13:47:50 -0700113
Abhishek Patelc7229812022-02-01 10:07:15 -0600114/**
115 * @brief Maps user group names retrieved from D-Bus object to
116 * Account Types.
117 *
118 * @param[in] userGroups List of User groups
119 * @param[out] res AccountTypes populated
120 *
121 * @return true in case of success, false if UserGroups contains
122 * invalid group name(s).
123 */
124inline bool translateUserGroup(const std::vector<std::string>& userGroups,
125 crow::Response& res)
126{
127 std::vector<std::string> accountTypes;
128 for (const auto& userGroup : userGroups)
129 {
130 if (userGroup == "redfish")
131 {
132 accountTypes.emplace_back("Redfish");
133 accountTypes.emplace_back("WebUI");
134 }
135 else if (userGroup == "ipmi")
136 {
137 accountTypes.emplace_back("IPMI");
138 }
139 else if (userGroup == "ssh")
140 {
141 accountTypes.emplace_back("HostConsole");
142 accountTypes.emplace_back("ManagerConsole");
143 }
144 else if (userGroup == "web")
145 {
146 // 'web' is one of the valid groups in the UserGroups property of
147 // the user account in the D-Bus object. This group is currently not
148 // doing anything, and is considered to be equivalent to 'redfish'.
149 // 'redfish' user group is mapped to 'Redfish'and 'WebUI'
150 // AccountTypes, so do nothing here...
151 }
152 else
153 {
154 // Invalid user group name. Caller throws an excption.
155 return false;
156 }
157 }
158
159 res.jsonValue["AccountTypes"] = std::move(accountTypes);
160 return true;
161}
162
zhanghch058d1b46d2021-04-01 11:18:24 +0800163inline void userErrorMessageHandler(
164 const sd_bus_error* e, const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
165 const std::string& newUser, const std::string& username)
jayaprakash Mutyala66b5ca72019-08-07 20:26:37 +0000166{
jayaprakash Mutyala66b5ca72019-08-07 20:26:37 +0000167 if (e == nullptr)
168 {
169 messages::internalError(asyncResp->res);
170 return;
171 }
172
Manojkiran Eda055806b2020-11-03 09:36:28 +0530173 const char* errorMessage = e->name;
jayaprakash Mutyala66b5ca72019-08-07 20:26:37 +0000174 if (strcmp(errorMessage,
175 "xyz.openbmc_project.User.Common.Error.UserNameExists") == 0)
176 {
Jiaqing Zhaod8a5d5d2022-08-05 16:21:51 +0800177 messages::resourceAlreadyExists(asyncResp->res, "ManagerAccount",
jayaprakash Mutyala66b5ca72019-08-07 20:26:37 +0000178 "UserName", newUser);
179 }
180 else if (strcmp(errorMessage, "xyz.openbmc_project.User.Common.Error."
181 "UserNameDoesNotExist") == 0)
182 {
Jiaqing Zhaod8a5d5d2022-08-05 16:21:51 +0800183 messages::resourceNotFound(asyncResp->res, "ManagerAccount", username);
jayaprakash Mutyala66b5ca72019-08-07 20:26:37 +0000184 }
Ed Tanousd4d25792020-09-29 15:15:03 -0700185 else if ((strcmp(errorMessage,
186 "xyz.openbmc_project.Common.Error.InvalidArgument") ==
187 0) ||
George Liu0fda0f12021-11-16 10:06:17 +0800188 (strcmp(
189 errorMessage,
190 "xyz.openbmc_project.User.Common.Error.UserNameGroupFail") ==
191 0))
jayaprakash Mutyala66b5ca72019-08-07 20:26:37 +0000192 {
193 messages::propertyValueFormatError(asyncResp->res, newUser, "UserName");
194 }
195 else if (strcmp(errorMessage,
196 "xyz.openbmc_project.User.Common.Error.NoResource") == 0)
197 {
198 messages::createLimitReachedForResource(asyncResp->res);
199 }
jayaprakash Mutyala66b5ca72019-08-07 20:26:37 +0000200 else
201 {
202 messages::internalError(asyncResp->res);
203 }
jayaprakash Mutyala66b5ca72019-08-07 20:26:37 +0000204}
205
Ed Tanous81ce6092020-12-17 16:54:55 +0000206inline void parseLDAPConfigData(nlohmann::json& jsonResponse,
Ed Tanous23a21a12020-07-25 04:45:05 +0000207 const LDAPConfigData& confData,
208 const std::string& ldapType)
Ratan Gupta6973a582018-12-13 18:25:44 +0530209{
Ratan Guptaab828d72019-04-22 14:18:33 +0530210 std::string service =
211 (ldapType == "LDAP") ? "LDAPService" : "ActiveDirectoryService";
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600212
Ed Tanous14766872022-03-15 10:44:42 -0700213 nlohmann::json& ldap = jsonResponse[ldapType];
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600214
Ed Tanous14766872022-03-15 10:44:42 -0700215 ldap["ServiceEnabled"] = confData.serviceEnabled;
216 ldap["ServiceAddresses"] = nlohmann::json::array({confData.uri});
Ed Tanous0ec8b832022-03-14 14:56:47 -0700217 ldap["Authentication"]["AuthenticationType"] =
218 account_service::AuthenticationTypes::UsernameAndPassword;
Ed Tanous14766872022-03-15 10:44:42 -0700219 ldap["Authentication"]["Username"] = confData.bindDN;
220 ldap["Authentication"]["Password"] = nullptr;
221
222 ldap["LDAPService"]["SearchSettings"]["BaseDistinguishedNames"] =
223 nlohmann::json::array({confData.baseDN});
224 ldap["LDAPService"]["SearchSettings"]["UsernameAttribute"] =
225 confData.userNameAttribute;
226 ldap["LDAPService"]["SearchSettings"]["GroupsAttribute"] =
227 confData.groupAttribute;
228
229 nlohmann::json& roleMapArray = ldap["RemoteRoleMapping"];
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600230 roleMapArray = nlohmann::json::array();
Ed Tanous9eb808c2022-01-25 10:19:23 -0800231 for (const auto& obj : confData.groupRoleList)
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600232 {
233 BMCWEB_LOG_DEBUG << "Pushing the data groupName="
234 << obj.second.groupName << "\n";
Ed Tanous613dabe2022-07-09 11:17:36 -0700235
Ed Tanous613dabe2022-07-09 11:17:36 -0700236 nlohmann::json::object_t remoteGroup;
237 remoteGroup["RemoteGroup"] = obj.second.groupName;
Jorge Cisneros329f0342022-11-04 16:26:25 +0000238 remoteGroup["LocalRole"] = getRoleIdFromPrivilege(obj.second.privilege);
239 roleMapArray.emplace_back(std::move(remoteGroup));
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600240 }
Ratan Gupta6973a582018-12-13 18:25:44 +0530241}
242
243/**
Ratan Gupta06785242019-07-26 22:30:16 +0530244 * @brief validates given JSON input and then calls appropriate method to
245 * create, to delete or to set Rolemapping object based on the given input.
246 *
247 */
Ed Tanous23a21a12020-07-25 04:45:05 +0000248inline void handleRoleMapPatch(
zhanghch058d1b46d2021-04-01 11:18:24 +0800249 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ratan Gupta06785242019-07-26 22:30:16 +0530250 const std::vector<std::pair<std::string, LDAPRoleMapData>>& roleMapObjData,
Ed Tanousf23b7292020-10-15 09:41:17 -0700251 const std::string& serverType, const std::vector<nlohmann::json>& input)
Ratan Gupta06785242019-07-26 22:30:16 +0530252{
253 for (size_t index = 0; index < input.size(); index++)
254 {
Ed Tanousf23b7292020-10-15 09:41:17 -0700255 const nlohmann::json& thisJson = input[index];
Ratan Gupta06785242019-07-26 22:30:16 +0530256
257 if (thisJson.is_null())
258 {
259 // delete the existing object
260 if (index < roleMapObjData.size())
261 {
262 crow::connections::systemBus->async_method_call(
263 [asyncResp, roleMapObjData, serverType,
264 index](const boost::system::error_code ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700265 if (ec)
266 {
267 BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
268 messages::internalError(asyncResp->res);
269 return;
270 }
271 asyncResp->res
272 .jsonValue[serverType]["RemoteRoleMapping"][index] =
273 nullptr;
Ratan Gupta06785242019-07-26 22:30:16 +0530274 },
275 ldapDbusService, roleMapObjData[index].first,
276 "xyz.openbmc_project.Object.Delete", "Delete");
277 }
278 else
279 {
280 BMCWEB_LOG_ERROR << "Can't delete the object";
281 messages::propertyValueTypeError(
Ed Tanous71f52d92021-02-19 08:51:17 -0800282 asyncResp->res,
283 thisJson.dump(2, ' ', true,
284 nlohmann::json::error_handler_t::replace),
Ratan Gupta06785242019-07-26 22:30:16 +0530285 "RemoteRoleMapping/" + std::to_string(index));
286 return;
287 }
288 }
289 else if (thisJson.empty())
290 {
291 // Don't do anything for the empty objects,parse next json
292 // eg {"RemoteRoleMapping",[{}]}
293 }
294 else
295 {
296 // update/create the object
297 std::optional<std::string> remoteGroup;
298 std::optional<std::string> localRole;
299
Ed Tanousf23b7292020-10-15 09:41:17 -0700300 // This is a copy, but it's required in this case because of how
301 // readJson is structured
302 nlohmann::json thisJsonCopy = thisJson;
303 if (!json_util::readJson(thisJsonCopy, asyncResp->res,
304 "RemoteGroup", remoteGroup, "LocalRole",
305 localRole))
Ratan Gupta06785242019-07-26 22:30:16 +0530306 {
307 continue;
308 }
309
310 // Update existing RoleMapping Object
311 if (index < roleMapObjData.size())
312 {
313 BMCWEB_LOG_DEBUG << "Update Role Map Object";
314 // If "RemoteGroup" info is provided
315 if (remoteGroup)
316 {
317 crow::connections::systemBus->async_method_call(
318 [asyncResp, roleMapObjData, serverType, index,
319 remoteGroup](const boost::system::error_code ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700320 if (ec)
321 {
322 BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
323 messages::internalError(asyncResp->res);
324 return;
325 }
326 asyncResp->res
327 .jsonValue[serverType]["RemoteRoleMapping"][index]
328 ["RemoteGroup"] = *remoteGroup;
Ratan Gupta06785242019-07-26 22:30:16 +0530329 },
330 ldapDbusService, roleMapObjData[index].first,
331 propertyInterface, "Set",
332 "xyz.openbmc_project.User.PrivilegeMapperEntry",
333 "GroupName",
Ed Tanous168e20c2021-12-13 14:39:53 -0800334 dbus::utility::DbusVariantType(
335 std::move(*remoteGroup)));
Ratan Gupta06785242019-07-26 22:30:16 +0530336 }
337
338 // If "LocalRole" info is provided
339 if (localRole)
340 {
341 crow::connections::systemBus->async_method_call(
342 [asyncResp, roleMapObjData, serverType, index,
343 localRole](const boost::system::error_code ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700344 if (ec)
345 {
346 BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
347 messages::internalError(asyncResp->res);
348 return;
349 }
350 asyncResp->res
351 .jsonValue[serverType]["RemoteRoleMapping"][index]
352 ["LocalRole"] = *localRole;
Ratan Gupta06785242019-07-26 22:30:16 +0530353 },
354 ldapDbusService, roleMapObjData[index].first,
355 propertyInterface, "Set",
356 "xyz.openbmc_project.User.PrivilegeMapperEntry",
357 "Privilege",
Ed Tanous168e20c2021-12-13 14:39:53 -0800358 dbus::utility::DbusVariantType(
Ratan Gupta06785242019-07-26 22:30:16 +0530359 getPrivilegeFromRoleId(std::move(*localRole))));
360 }
361 }
362 // Create a new RoleMapping Object.
363 else
364 {
365 BMCWEB_LOG_DEBUG
366 << "setRoleMappingProperties: Creating new Object";
367 std::string pathString =
368 "RemoteRoleMapping/" + std::to_string(index);
369
370 if (!localRole)
371 {
372 messages::propertyMissing(asyncResp->res,
373 pathString + "/LocalRole");
374 continue;
375 }
376 if (!remoteGroup)
377 {
378 messages::propertyMissing(asyncResp->res,
379 pathString + "/RemoteGroup");
380 continue;
381 }
382
383 std::string dbusObjectPath;
384 if (serverType == "ActiveDirectory")
385 {
Ed Tanous2c70f802020-09-28 14:29:23 -0700386 dbusObjectPath = adConfigObject;
Ratan Gupta06785242019-07-26 22:30:16 +0530387 }
388 else if (serverType == "LDAP")
389 {
Ed Tanous23a21a12020-07-25 04:45:05 +0000390 dbusObjectPath = ldapConfigObjectName;
Ratan Gupta06785242019-07-26 22:30:16 +0530391 }
392
393 BMCWEB_LOG_DEBUG << "Remote Group=" << *remoteGroup
394 << ",LocalRole=" << *localRole;
395
396 crow::connections::systemBus->async_method_call(
Ed Tanous271584a2019-07-09 16:24:22 -0700397 [asyncResp, serverType, localRole,
Ratan Gupta06785242019-07-26 22:30:16 +0530398 remoteGroup](const boost::system::error_code ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700399 if (ec)
400 {
401 BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
402 messages::internalError(asyncResp->res);
403 return;
404 }
405 nlohmann::json& remoteRoleJson =
406 asyncResp->res
407 .jsonValue[serverType]["RemoteRoleMapping"];
408 nlohmann::json::object_t roleMapEntry;
409 roleMapEntry["LocalRole"] = *localRole;
410 roleMapEntry["RemoteGroup"] = *remoteGroup;
411 remoteRoleJson.push_back(std::move(roleMapEntry));
Ratan Gupta06785242019-07-26 22:30:16 +0530412 },
413 ldapDbusService, dbusObjectPath, ldapPrivMapperInterface,
Ed Tanous3174e4d2020-10-07 11:41:22 -0700414 "Create", *remoteGroup,
Ratan Gupta06785242019-07-26 22:30:16 +0530415 getPrivilegeFromRoleId(std::move(*localRole)));
416 }
417 }
418 }
419}
420
421/**
Ratan Gupta6973a582018-12-13 18:25:44 +0530422 * Function that retrieves all properties for LDAP config object
423 * into JSON
424 */
425template <typename CallbackFunc>
426inline void getLDAPConfigData(const std::string& ldapType,
427 CallbackFunc&& callback)
428{
Ratan Guptaab828d72019-04-22 14:18:33 +0530429
George Liu2b731192023-01-11 16:27:13 +0800430 constexpr std::array<std::string_view, 2> interfaces = {
431 ldapEnableInterface, ldapConfigInterface};
Ratan Gupta6973a582018-12-13 18:25:44 +0530432
George Liu2b731192023-01-11 16:27:13 +0800433 dbus::utility::getDbusObject(
434 ldapConfigObjectName, interfaces,
435 [callback, ldapType](const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800436 const dbus::utility::MapperGetObject& resp) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700437 if (ec || resp.empty())
438 {
439 BMCWEB_LOG_ERROR
440 << "DBUS response error during getting of service name: " << ec;
441 LDAPConfigData empty{};
442 callback(false, empty, ldapType);
443 return;
444 }
445 std::string service = resp.begin()->first;
446 crow::connections::systemBus->async_method_call(
447 [callback,
448 ldapType](const boost::system::error_code errorCode,
449 const dbus::utility::ManagedObjectType& ldapObjects) {
450 LDAPConfigData confData{};
451 if (errorCode)
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600452 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700453 callback(false, confData, ldapType);
454 BMCWEB_LOG_ERROR << "D-Bus responses error: " << errorCode;
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600455 return;
456 }
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600457
Ed Tanous002d39b2022-05-31 08:59:27 -0700458 std::string ldapDbusType;
459 std::string searchString;
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600460
Ed Tanous002d39b2022-05-31 08:59:27 -0700461 if (ldapType == "LDAP")
462 {
463 ldapDbusType =
464 "xyz.openbmc_project.User.Ldap.Config.Type.OpenLdap";
465 searchString = "openldap";
466 }
467 else if (ldapType == "ActiveDirectory")
468 {
469 ldapDbusType =
470 "xyz.openbmc_project.User.Ldap.Config.Type.ActiveDirectory";
471 searchString = "active_directory";
472 }
473 else
474 {
475 BMCWEB_LOG_ERROR << "Can't get the DbusType for the given type="
476 << ldapType;
477 callback(false, confData, ldapType);
478 return;
479 }
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600480
Ed Tanous002d39b2022-05-31 08:59:27 -0700481 std::string ldapEnableInterfaceStr = ldapEnableInterface;
482 std::string ldapConfigInterfaceStr = ldapConfigInterface;
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600483
Ed Tanous002d39b2022-05-31 08:59:27 -0700484 for (const auto& object : ldapObjects)
485 {
486 // let's find the object whose ldap type is equal to the
487 // given type
488 if (object.first.str.find(searchString) == std::string::npos)
489 {
490 continue;
491 }
492
493 for (const auto& interface : object.second)
494 {
495 if (interface.first == ldapEnableInterfaceStr)
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600496 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700497 // rest of the properties are string.
498 for (const auto& property : interface.second)
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600499 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700500 if (property.first == "Enabled")
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600501 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700502 const bool* value =
503 std::get_if<bool>(&property.second);
504 if (value == nullptr)
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600505 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700506 continue;
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600507 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700508 confData.serviceEnabled = *value;
509 break;
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600510 }
511 }
512 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700513 else if (interface.first == ldapConfigInterfaceStr)
514 {
515
516 for (const auto& property : interface.second)
517 {
518 const std::string* strValue =
519 std::get_if<std::string>(&property.second);
520 if (strValue == nullptr)
521 {
522 continue;
523 }
524 if (property.first == "LDAPServerURI")
525 {
526 confData.uri = *strValue;
527 }
528 else if (property.first == "LDAPBindDN")
529 {
530 confData.bindDN = *strValue;
531 }
532 else if (property.first == "LDAPBaseDN")
533 {
534 confData.baseDN = *strValue;
535 }
536 else if (property.first == "LDAPSearchScope")
537 {
538 confData.searchScope = *strValue;
539 }
540 else if (property.first == "GroupNameAttribute")
541 {
542 confData.groupAttribute = *strValue;
543 }
544 else if (property.first == "UserNameAttribute")
545 {
546 confData.userNameAttribute = *strValue;
547 }
548 else if (property.first == "LDAPType")
549 {
550 confData.serverType = *strValue;
551 }
552 }
553 }
554 else if (interface.first ==
555 "xyz.openbmc_project.User.PrivilegeMapperEntry")
556 {
557 LDAPRoleMapData roleMapData{};
558 for (const auto& property : interface.second)
559 {
560 const std::string* strValue =
561 std::get_if<std::string>(&property.second);
562
563 if (strValue == nullptr)
564 {
565 continue;
566 }
567
568 if (property.first == "GroupName")
569 {
570 roleMapData.groupName = *strValue;
571 }
572 else if (property.first == "Privilege")
573 {
574 roleMapData.privilege = *strValue;
575 }
576 }
577
578 confData.groupRoleList.emplace_back(object.first.str,
579 roleMapData);
580 }
581 }
582 }
583 callback(true, confData, ldapType);
584 },
585 service, ldapRootObject, dbusObjManagerIntf, "GetManagedObjects");
George Liu2b731192023-01-11 16:27:13 +0800586 });
Ratan Gupta6973a582018-12-13 18:25:44 +0530587}
588
Ed Tanous6c51eab2021-06-03 12:30:29 -0700589/**
590 * @brief parses the authentication section under the LDAP
591 * @param input JSON data
592 * @param asyncResp pointer to the JSON response
593 * @param userName userName to be filled from the given JSON.
594 * @param password password to be filled from the given JSON.
595 */
Ed Tanous4f48d5f2021-06-21 08:27:45 -0700596inline void parseLDAPAuthenticationJson(
Ed Tanous6c51eab2021-06-03 12:30:29 -0700597 nlohmann::json input, const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
598 std::optional<std::string>& username, std::optional<std::string>& password)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700599{
Ed Tanous6c51eab2021-06-03 12:30:29 -0700600 std::optional<std::string> authType;
601
602 if (!json_util::readJson(input, asyncResp->res, "AuthenticationType",
603 authType, "Username", username, "Password",
604 password))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700605 {
Ed Tanous6c51eab2021-06-03 12:30:29 -0700606 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700607 }
Ed Tanous6c51eab2021-06-03 12:30:29 -0700608 if (!authType)
Ratan Gupta8a07d282019-03-16 08:33:47 +0530609 {
Ed Tanous6c51eab2021-06-03 12:30:29 -0700610 return;
Ratan Gupta8a07d282019-03-16 08:33:47 +0530611 }
Ed Tanous6c51eab2021-06-03 12:30:29 -0700612 if (*authType != "UsernameAndPassword")
Ratan Gupta8a07d282019-03-16 08:33:47 +0530613 {
Ed Tanous6c51eab2021-06-03 12:30:29 -0700614 messages::propertyValueNotInList(asyncResp->res, *authType,
615 "AuthenticationType");
616 return;
Ratan Gupta8a07d282019-03-16 08:33:47 +0530617 }
Ed Tanous6c51eab2021-06-03 12:30:29 -0700618}
619/**
620 * @brief parses the LDAPService section under the LDAP
621 * @param input JSON data
622 * @param asyncResp pointer to the JSON response
623 * @param baseDNList baseDN to be filled from the given JSON.
624 * @param userNameAttribute userName to be filled from the given JSON.
625 * @param groupaAttribute password to be filled from the given JSON.
626 */
Ratan Gupta8a07d282019-03-16 08:33:47 +0530627
Ed Tanous4f48d5f2021-06-21 08:27:45 -0700628inline void
629 parseLDAPServiceJson(nlohmann::json input,
630 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
631 std::optional<std::vector<std::string>>& baseDNList,
632 std::optional<std::string>& userNameAttribute,
633 std::optional<std::string>& groupsAttribute)
Ed Tanous6c51eab2021-06-03 12:30:29 -0700634{
635 std::optional<nlohmann::json> searchSettings;
636
637 if (!json_util::readJson(input, asyncResp->res, "SearchSettings",
638 searchSettings))
Ratan Gupta8a07d282019-03-16 08:33:47 +0530639 {
Ed Tanous6c51eab2021-06-03 12:30:29 -0700640 return;
Ratan Gupta8a07d282019-03-16 08:33:47 +0530641 }
Ed Tanous6c51eab2021-06-03 12:30:29 -0700642 if (!searchSettings)
Ratan Gupta8a07d282019-03-16 08:33:47 +0530643 {
Ed Tanous6c51eab2021-06-03 12:30:29 -0700644 return;
Ratan Gupta8a07d282019-03-16 08:33:47 +0530645 }
Ed Tanous6c51eab2021-06-03 12:30:29 -0700646 if (!json_util::readJson(*searchSettings, asyncResp->res,
647 "BaseDistinguishedNames", baseDNList,
648 "UsernameAttribute", userNameAttribute,
649 "GroupsAttribute", groupsAttribute))
Ratan Gupta8a07d282019-03-16 08:33:47 +0530650 {
Ed Tanous6c51eab2021-06-03 12:30:29 -0700651 return;
Ratan Gupta8a07d282019-03-16 08:33:47 +0530652 }
Ed Tanous6c51eab2021-06-03 12:30:29 -0700653}
654/**
655 * @brief updates the LDAP server address and updates the
656 json response with the new value.
657 * @param serviceAddressList address to be updated.
658 * @param asyncResp pointer to the JSON response
659 * @param ldapServerElementName Type of LDAP
660 server(openLDAP/ActiveDirectory)
661 */
Ratan Gupta8a07d282019-03-16 08:33:47 +0530662
Ed Tanous4f48d5f2021-06-21 08:27:45 -0700663inline void handleServiceAddressPatch(
Ed Tanous6c51eab2021-06-03 12:30:29 -0700664 const std::vector<std::string>& serviceAddressList,
665 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
666 const std::string& ldapServerElementName,
667 const std::string& ldapConfigObject)
668{
669 crow::connections::systemBus->async_method_call(
670 [asyncResp, ldapServerElementName,
671 serviceAddressList](const boost::system::error_code ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700672 if (ec)
673 {
674 BMCWEB_LOG_DEBUG
675 << "Error Occurred in updating the service address";
676 messages::internalError(asyncResp->res);
677 return;
678 }
679 std::vector<std::string> modifiedserviceAddressList = {
680 serviceAddressList.front()};
681 asyncResp->res.jsonValue[ldapServerElementName]["ServiceAddresses"] =
682 modifiedserviceAddressList;
683 if ((serviceAddressList).size() > 1)
684 {
685 messages::propertyValueModified(asyncResp->res, "ServiceAddresses",
686 serviceAddressList.front());
687 }
688 BMCWEB_LOG_DEBUG << "Updated the service address";
Ed Tanous6c51eab2021-06-03 12:30:29 -0700689 },
690 ldapDbusService, ldapConfigObject, propertyInterface, "Set",
691 ldapConfigInterface, "LDAPServerURI",
Ed Tanous168e20c2021-12-13 14:39:53 -0800692 dbus::utility::DbusVariantType(serviceAddressList.front()));
Ed Tanous6c51eab2021-06-03 12:30:29 -0700693}
694/**
695 * @brief updates the LDAP Bind DN and updates the
696 json response with the new value.
697 * @param username name of the user which needs to be updated.
698 * @param asyncResp pointer to the JSON response
699 * @param ldapServerElementName Type of LDAP
700 server(openLDAP/ActiveDirectory)
701 */
Ratan Gupta8a07d282019-03-16 08:33:47 +0530702
Ed Tanous4f48d5f2021-06-21 08:27:45 -0700703inline void
704 handleUserNamePatch(const std::string& username,
705 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
706 const std::string& ldapServerElementName,
707 const std::string& ldapConfigObject)
Ed Tanous6c51eab2021-06-03 12:30:29 -0700708{
709 crow::connections::systemBus->async_method_call(
710 [asyncResp, username,
711 ldapServerElementName](const boost::system::error_code ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700712 if (ec)
713 {
714 BMCWEB_LOG_DEBUG << "Error occurred in updating the username";
715 messages::internalError(asyncResp->res);
716 return;
717 }
718 asyncResp->res
719 .jsonValue[ldapServerElementName]["Authentication"]["Username"] =
720 username;
721 BMCWEB_LOG_DEBUG << "Updated the username";
Ed Tanous6c51eab2021-06-03 12:30:29 -0700722 },
723 ldapDbusService, ldapConfigObject, propertyInterface, "Set",
Ed Tanous168e20c2021-12-13 14:39:53 -0800724 ldapConfigInterface, "LDAPBindDN",
725 dbus::utility::DbusVariantType(username));
Ed Tanous6c51eab2021-06-03 12:30:29 -0700726}
727
728/**
729 * @brief updates the LDAP password
730 * @param password : ldap password which needs to be updated.
731 * @param asyncResp pointer to the JSON response
732 * @param ldapServerElementName Type of LDAP
733 * server(openLDAP/ActiveDirectory)
734 */
735
Ed Tanous4f48d5f2021-06-21 08:27:45 -0700736inline void
737 handlePasswordPatch(const std::string& password,
738 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
739 const std::string& ldapServerElementName,
740 const std::string& ldapConfigObject)
Ed Tanous6c51eab2021-06-03 12:30:29 -0700741{
742 crow::connections::systemBus->async_method_call(
743 [asyncResp, password,
744 ldapServerElementName](const boost::system::error_code ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700745 if (ec)
746 {
747 BMCWEB_LOG_DEBUG << "Error occurred in updating the password";
748 messages::internalError(asyncResp->res);
749 return;
750 }
751 asyncResp->res
752 .jsonValue[ldapServerElementName]["Authentication"]["Password"] =
753 "";
754 BMCWEB_LOG_DEBUG << "Updated the password";
Ed Tanous6c51eab2021-06-03 12:30:29 -0700755 },
756 ldapDbusService, ldapConfigObject, propertyInterface, "Set",
757 ldapConfigInterface, "LDAPBindDNPassword",
Ed Tanous168e20c2021-12-13 14:39:53 -0800758 dbus::utility::DbusVariantType(password));
Ed Tanous6c51eab2021-06-03 12:30:29 -0700759}
760
761/**
762 * @brief updates the LDAP BaseDN and updates the
763 json response with the new value.
764 * @param baseDNList baseDN list which needs to be updated.
765 * @param asyncResp pointer to the JSON response
766 * @param ldapServerElementName Type of LDAP
767 server(openLDAP/ActiveDirectory)
768 */
769
Ed Tanous4f48d5f2021-06-21 08:27:45 -0700770inline void
771 handleBaseDNPatch(const std::vector<std::string>& baseDNList,
772 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
773 const std::string& ldapServerElementName,
774 const std::string& ldapConfigObject)
Ed Tanous6c51eab2021-06-03 12:30:29 -0700775{
776 crow::connections::systemBus->async_method_call(
777 [asyncResp, baseDNList,
778 ldapServerElementName](const boost::system::error_code ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700779 if (ec)
780 {
781 BMCWEB_LOG_DEBUG << "Error Occurred in Updating the base DN";
782 messages::internalError(asyncResp->res);
783 return;
784 }
785 auto& serverTypeJson = asyncResp->res.jsonValue[ldapServerElementName];
786 auto& searchSettingsJson =
787 serverTypeJson["LDAPService"]["SearchSettings"];
788 std::vector<std::string> modifiedBaseDNList = {baseDNList.front()};
789 searchSettingsJson["BaseDistinguishedNames"] = modifiedBaseDNList;
790 if (baseDNList.size() > 1)
791 {
792 messages::propertyValueModified(
793 asyncResp->res, "BaseDistinguishedNames", baseDNList.front());
794 }
795 BMCWEB_LOG_DEBUG << "Updated the base DN";
Ed Tanous6c51eab2021-06-03 12:30:29 -0700796 },
797 ldapDbusService, ldapConfigObject, propertyInterface, "Set",
798 ldapConfigInterface, "LDAPBaseDN",
Ed Tanous168e20c2021-12-13 14:39:53 -0800799 dbus::utility::DbusVariantType(baseDNList.front()));
Ed Tanous6c51eab2021-06-03 12:30:29 -0700800}
801/**
802 * @brief updates the LDAP user name attribute and updates the
803 json response with the new value.
804 * @param userNameAttribute attribute to be updated.
805 * @param asyncResp pointer to the JSON response
806 * @param ldapServerElementName Type of LDAP
807 server(openLDAP/ActiveDirectory)
808 */
809
Ed Tanous4f48d5f2021-06-21 08:27:45 -0700810inline void
811 handleUserNameAttrPatch(const std::string& userNameAttribute,
812 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
813 const std::string& ldapServerElementName,
814 const std::string& ldapConfigObject)
Ed Tanous6c51eab2021-06-03 12:30:29 -0700815{
816 crow::connections::systemBus->async_method_call(
817 [asyncResp, userNameAttribute,
818 ldapServerElementName](const boost::system::error_code ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700819 if (ec)
820 {
821 BMCWEB_LOG_DEBUG << "Error Occurred in Updating the "
822 "username attribute";
823 messages::internalError(asyncResp->res);
824 return;
825 }
826 auto& serverTypeJson = asyncResp->res.jsonValue[ldapServerElementName];
827 auto& searchSettingsJson =
828 serverTypeJson["LDAPService"]["SearchSettings"];
829 searchSettingsJson["UsernameAttribute"] = userNameAttribute;
830 BMCWEB_LOG_DEBUG << "Updated the user name attr.";
Ed Tanous6c51eab2021-06-03 12:30:29 -0700831 },
832 ldapDbusService, ldapConfigObject, propertyInterface, "Set",
833 ldapConfigInterface, "UserNameAttribute",
Ed Tanous168e20c2021-12-13 14:39:53 -0800834 dbus::utility::DbusVariantType(userNameAttribute));
Ed Tanous6c51eab2021-06-03 12:30:29 -0700835}
836/**
837 * @brief updates the LDAP group attribute and updates the
838 json response with the new value.
839 * @param groupsAttribute attribute to be updated.
840 * @param asyncResp pointer to the JSON response
841 * @param ldapServerElementName Type of LDAP
842 server(openLDAP/ActiveDirectory)
843 */
844
Ed Tanous4f48d5f2021-06-21 08:27:45 -0700845inline void handleGroupNameAttrPatch(
Ed Tanous6c51eab2021-06-03 12:30:29 -0700846 const std::string& groupsAttribute,
847 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
848 const std::string& ldapServerElementName,
849 const std::string& ldapConfigObject)
850{
851 crow::connections::systemBus->async_method_call(
852 [asyncResp, groupsAttribute,
853 ldapServerElementName](const boost::system::error_code ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700854 if (ec)
855 {
856 BMCWEB_LOG_DEBUG << "Error Occurred in Updating the "
857 "groupname attribute";
858 messages::internalError(asyncResp->res);
859 return;
860 }
861 auto& serverTypeJson = asyncResp->res.jsonValue[ldapServerElementName];
862 auto& searchSettingsJson =
863 serverTypeJson["LDAPService"]["SearchSettings"];
864 searchSettingsJson["GroupsAttribute"] = groupsAttribute;
865 BMCWEB_LOG_DEBUG << "Updated the groupname attr";
Ed Tanous6c51eab2021-06-03 12:30:29 -0700866 },
867 ldapDbusService, ldapConfigObject, propertyInterface, "Set",
868 ldapConfigInterface, "GroupNameAttribute",
Ed Tanous168e20c2021-12-13 14:39:53 -0800869 dbus::utility::DbusVariantType(groupsAttribute));
Ed Tanous6c51eab2021-06-03 12:30:29 -0700870}
871/**
872 * @brief updates the LDAP service enable and updates the
873 json response with the new value.
874 * @param input JSON data.
875 * @param asyncResp pointer to the JSON response
876 * @param ldapServerElementName Type of LDAP
877 server(openLDAP/ActiveDirectory)
878 */
879
Ed Tanous4f48d5f2021-06-21 08:27:45 -0700880inline void handleServiceEnablePatch(
Ed Tanous6c51eab2021-06-03 12:30:29 -0700881 bool serviceEnabled, const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
882 const std::string& ldapServerElementName,
883 const std::string& ldapConfigObject)
884{
885 crow::connections::systemBus->async_method_call(
886 [asyncResp, serviceEnabled,
887 ldapServerElementName](const boost::system::error_code ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700888 if (ec)
889 {
890 BMCWEB_LOG_DEBUG << "Error Occurred in Updating the service enable";
891 messages::internalError(asyncResp->res);
892 return;
893 }
894 asyncResp->res.jsonValue[ldapServerElementName]["ServiceEnabled"] =
895 serviceEnabled;
896 BMCWEB_LOG_DEBUG << "Updated Service enable = " << serviceEnabled;
Ed Tanous6c51eab2021-06-03 12:30:29 -0700897 },
898 ldapDbusService, ldapConfigObject, propertyInterface, "Set",
Ed Tanous168e20c2021-12-13 14:39:53 -0800899 ldapEnableInterface, "Enabled",
900 dbus::utility::DbusVariantType(serviceEnabled));
Ed Tanous6c51eab2021-06-03 12:30:29 -0700901}
902
Ed Tanous4f48d5f2021-06-21 08:27:45 -0700903inline void
904 handleAuthMethodsPatch(nlohmann::json& input,
905 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Ed Tanous6c51eab2021-06-03 12:30:29 -0700906{
907 std::optional<bool> basicAuth;
908 std::optional<bool> cookie;
909 std::optional<bool> sessionToken;
910 std::optional<bool> xToken;
911 std::optional<bool> tls;
912
913 if (!json_util::readJson(input, asyncResp->res, "BasicAuth", basicAuth,
914 "Cookie", cookie, "SessionToken", sessionToken,
915 "XToken", xToken, "TLS", tls))
Ratan Gupta8a07d282019-03-16 08:33:47 +0530916 {
Ed Tanous6c51eab2021-06-03 12:30:29 -0700917 BMCWEB_LOG_ERROR << "Cannot read values from AuthMethod tag";
918 return;
919 }
920
921 // Make a copy of methods configuration
922 persistent_data::AuthConfigMethods authMethodsConfig =
923 persistent_data::SessionStore::getInstance().getAuthMethodsConfig();
924
925 if (basicAuth)
926 {
927#ifndef BMCWEB_ENABLE_BASIC_AUTHENTICATION
928 messages::actionNotSupported(
George Liu0fda0f12021-11-16 10:06:17 +0800929 asyncResp->res,
930 "Setting BasicAuth when basic-auth feature is disabled");
Ed Tanous6c51eab2021-06-03 12:30:29 -0700931 return;
932#endif
933 authMethodsConfig.basic = *basicAuth;
934 }
935
936 if (cookie)
937 {
938#ifndef BMCWEB_ENABLE_COOKIE_AUTHENTICATION
George Liu0fda0f12021-11-16 10:06:17 +0800939 messages::actionNotSupported(
940 asyncResp->res,
941 "Setting Cookie when cookie-auth feature is disabled");
Ed Tanous6c51eab2021-06-03 12:30:29 -0700942 return;
943#endif
944 authMethodsConfig.cookie = *cookie;
945 }
946
947 if (sessionToken)
948 {
949#ifndef BMCWEB_ENABLE_SESSION_AUTHENTICATION
950 messages::actionNotSupported(
George Liu0fda0f12021-11-16 10:06:17 +0800951 asyncResp->res,
952 "Setting SessionToken when session-auth feature is disabled");
Ed Tanous6c51eab2021-06-03 12:30:29 -0700953 return;
954#endif
955 authMethodsConfig.sessionToken = *sessionToken;
956 }
957
958 if (xToken)
959 {
960#ifndef BMCWEB_ENABLE_XTOKEN_AUTHENTICATION
George Liu0fda0f12021-11-16 10:06:17 +0800961 messages::actionNotSupported(
962 asyncResp->res,
963 "Setting XToken when xtoken-auth feature is disabled");
Ed Tanous6c51eab2021-06-03 12:30:29 -0700964 return;
965#endif
966 authMethodsConfig.xtoken = *xToken;
967 }
968
969 if (tls)
970 {
971#ifndef BMCWEB_ENABLE_MUTUAL_TLS_AUTHENTICATION
George Liu0fda0f12021-11-16 10:06:17 +0800972 messages::actionNotSupported(
973 asyncResp->res,
974 "Setting TLS when mutual-tls-auth feature is disabled");
Ed Tanous6c51eab2021-06-03 12:30:29 -0700975 return;
976#endif
977 authMethodsConfig.tls = *tls;
978 }
979
980 if (!authMethodsConfig.basic && !authMethodsConfig.cookie &&
981 !authMethodsConfig.sessionToken && !authMethodsConfig.xtoken &&
982 !authMethodsConfig.tls)
983 {
984 // Do not allow user to disable everything
985 messages::actionNotSupported(asyncResp->res,
986 "of disabling all available methods");
987 return;
988 }
989
990 persistent_data::SessionStore::getInstance().updateAuthMethodsConfig(
991 authMethodsConfig);
992 // Save configuration immediately
993 persistent_data::getConfig().writeData();
994
995 messages::success(asyncResp->res);
996}
997
998/**
999 * @brief Get the required values from the given JSON, validates the
1000 * value and create the LDAP config object.
1001 * @param input JSON data
1002 * @param asyncResp pointer to the JSON response
1003 * @param serverType Type of LDAP server(openLDAP/ActiveDirectory)
1004 */
1005
1006inline void handleLDAPPatch(nlohmann::json& input,
1007 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1008 const std::string& serverType)
1009{
1010 std::string dbusObjectPath;
1011 if (serverType == "ActiveDirectory")
1012 {
1013 dbusObjectPath = adConfigObject;
1014 }
1015 else if (serverType == "LDAP")
1016 {
1017 dbusObjectPath = ldapConfigObjectName;
1018 }
1019 else
1020 {
1021 return;
1022 }
1023
1024 std::optional<nlohmann::json> authentication;
1025 std::optional<nlohmann::json> ldapService;
1026 std::optional<std::vector<std::string>> serviceAddressList;
1027 std::optional<bool> serviceEnabled;
1028 std::optional<std::vector<std::string>> baseDNList;
1029 std::optional<std::string> userNameAttribute;
1030 std::optional<std::string> groupsAttribute;
1031 std::optional<std::string> userName;
1032 std::optional<std::string> password;
1033 std::optional<std::vector<nlohmann::json>> remoteRoleMapData;
1034
1035 if (!json_util::readJson(input, asyncResp->res, "Authentication",
1036 authentication, "LDAPService", ldapService,
1037 "ServiceAddresses", serviceAddressList,
1038 "ServiceEnabled", serviceEnabled,
1039 "RemoteRoleMapping", remoteRoleMapData))
1040 {
1041 return;
1042 }
1043
1044 if (authentication)
1045 {
1046 parseLDAPAuthenticationJson(*authentication, asyncResp, userName,
1047 password);
1048 }
1049 if (ldapService)
1050 {
1051 parseLDAPServiceJson(*ldapService, asyncResp, baseDNList,
1052 userNameAttribute, groupsAttribute);
1053 }
1054 if (serviceAddressList)
1055 {
Ed Tanous26f69762022-01-25 09:49:11 -08001056 if (serviceAddressList->empty())
Ratan Guptaeb2bbe52019-04-22 14:27:01 +05301057 {
Ed Tanous6c51eab2021-06-03 12:30:29 -07001058 messages::propertyValueNotInList(asyncResp->res, "[]",
1059 "ServiceAddress");
Ed Tanouscb13a392020-07-25 19:02:03 +00001060 return;
1061 }
Ed Tanous6c51eab2021-06-03 12:30:29 -07001062 }
1063 if (baseDNList)
1064 {
Ed Tanous26f69762022-01-25 09:49:11 -08001065 if (baseDNList->empty())
Ratan Gupta8a07d282019-03-16 08:33:47 +05301066 {
Ed Tanous6c51eab2021-06-03 12:30:29 -07001067 messages::propertyValueNotInList(asyncResp->res, "[]",
1068 "BaseDistinguishedNames");
Ratan Gupta8a07d282019-03-16 08:33:47 +05301069 return;
1070 }
Ed Tanous6c51eab2021-06-03 12:30:29 -07001071 }
Ratan Gupta8a07d282019-03-16 08:33:47 +05301072
Ed Tanous6c51eab2021-06-03 12:30:29 -07001073 // nothing to update, then return
1074 if (!userName && !password && !serviceAddressList && !baseDNList &&
1075 !userNameAttribute && !groupsAttribute && !serviceEnabled &&
1076 !remoteRoleMapData)
1077 {
1078 return;
1079 }
1080
1081 // Get the existing resource first then keep modifying
1082 // whenever any property gets updated.
Ed Tanous002d39b2022-05-31 08:59:27 -07001083 getLDAPConfigData(
1084 serverType,
1085 [asyncResp, userName, password, baseDNList, userNameAttribute,
1086 groupsAttribute, serviceAddressList, serviceEnabled, dbusObjectPath,
1087 remoteRoleMapData](bool success, const LDAPConfigData& confData,
1088 const std::string& serverT) {
Ed Tanous6c51eab2021-06-03 12:30:29 -07001089 if (!success)
Ratan Gupta8a07d282019-03-16 08:33:47 +05301090 {
Ed Tanous6c51eab2021-06-03 12:30:29 -07001091 messages::internalError(asyncResp->res);
1092 return;
Ratan Gupta8a07d282019-03-16 08:33:47 +05301093 }
Ed Tanous6c51eab2021-06-03 12:30:29 -07001094 parseLDAPConfigData(asyncResp->res.jsonValue, confData, serverT);
1095 if (confData.serviceEnabled)
Ratan Gupta8a07d282019-03-16 08:33:47 +05301096 {
Ed Tanous6c51eab2021-06-03 12:30:29 -07001097 // Disable the service first and update the rest of
1098 // the properties.
1099 handleServiceEnablePatch(false, asyncResp, serverT, dbusObjectPath);
Ratan Gupta8a07d282019-03-16 08:33:47 +05301100 }
Ed Tanous6c51eab2021-06-03 12:30:29 -07001101
Ratan Gupta8a07d282019-03-16 08:33:47 +05301102 if (serviceAddressList)
1103 {
Ed Tanous6c51eab2021-06-03 12:30:29 -07001104 handleServiceAddressPatch(*serviceAddressList, asyncResp, serverT,
1105 dbusObjectPath);
Ratan Gupta8a07d282019-03-16 08:33:47 +05301106 }
Ed Tanous6c51eab2021-06-03 12:30:29 -07001107 if (userName)
1108 {
1109 handleUserNamePatch(*userName, asyncResp, serverT, dbusObjectPath);
1110 }
1111 if (password)
1112 {
1113 handlePasswordPatch(*password, asyncResp, serverT, dbusObjectPath);
1114 }
1115
Ratan Gupta8a07d282019-03-16 08:33:47 +05301116 if (baseDNList)
1117 {
Ed Tanous6c51eab2021-06-03 12:30:29 -07001118 handleBaseDNPatch(*baseDNList, asyncResp, serverT, dbusObjectPath);
1119 }
1120 if (userNameAttribute)
1121 {
1122 handleUserNameAttrPatch(*userNameAttribute, asyncResp, serverT,
1123 dbusObjectPath);
1124 }
1125 if (groupsAttribute)
1126 {
1127 handleGroupNameAttrPatch(*groupsAttribute, asyncResp, serverT,
1128 dbusObjectPath);
1129 }
1130 if (serviceEnabled)
1131 {
1132 // if user has given the value as true then enable
1133 // the service. if user has given false then no-op
1134 // as service is already stopped.
1135 if (*serviceEnabled)
Ratan Gupta8a07d282019-03-16 08:33:47 +05301136 {
Ed Tanous6c51eab2021-06-03 12:30:29 -07001137 handleServiceEnablePatch(*serviceEnabled, asyncResp, serverT,
1138 dbusObjectPath);
Ratan Gupta8a07d282019-03-16 08:33:47 +05301139 }
1140 }
jayaprakash Mutyala96200602020-04-08 11:09:10 +00001141 else
1142 {
Ed Tanous6c51eab2021-06-03 12:30:29 -07001143 // if user has not given the service enabled value
1144 // then revert it to the same state as it was
1145 // before.
1146 handleServiceEnablePatch(confData.serviceEnabled, asyncResp,
1147 serverT, dbusObjectPath);
jayaprakash Mutyala96200602020-04-08 11:09:10 +00001148 }
Ed Tanous04ae99e2018-09-20 15:54:36 -07001149
Ed Tanous6c51eab2021-06-03 12:30:29 -07001150 if (remoteRoleMapData)
1151 {
1152 handleRoleMapPatch(asyncResp, confData.groupRoleList, serverT,
1153 *remoteRoleMapData);
1154 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001155 });
Ed Tanous6c51eab2021-06-03 12:30:29 -07001156}
1157
1158inline void updateUserProperties(std::shared_ptr<bmcweb::AsyncResp> asyncResp,
1159 const std::string& username,
Ed Tanous618c14b2022-06-30 17:44:25 -07001160 const std::optional<std::string>& password,
1161 const std::optional<bool>& enabled,
1162 const std::optional<std::string>& roleId,
1163 const std::optional<bool>& locked)
Ed Tanous6c51eab2021-06-03 12:30:29 -07001164{
P Dheeraj Srujan Kumarb477fd42021-12-16 07:17:51 +05301165 sdbusplus::message::object_path tempObjPath(rootUserDbusPath);
1166 tempObjPath /= username;
1167 std::string dbusObjectPath(tempObjPath);
Ed Tanous6c51eab2021-06-03 12:30:29 -07001168
1169 dbus::utility::checkDbusPathExists(
Ed Tanous618c14b2022-06-30 17:44:25 -07001170 dbusObjectPath, [dbusObjectPath, username, password, roleId, enabled,
1171 locked, asyncResp{std::move(asyncResp)}](int rc) {
1172 if (rc <= 0)
Ed Tanous6c51eab2021-06-03 12:30:29 -07001173 {
Jiaqing Zhaod8a5d5d2022-08-05 16:21:51 +08001174 messages::resourceNotFound(asyncResp->res, "ManagerAccount",
1175 username);
Ed Tanous6c51eab2021-06-03 12:30:29 -07001176 return;
1177 }
Ed Tanous6c51eab2021-06-03 12:30:29 -07001178
Ed Tanous618c14b2022-06-30 17:44:25 -07001179 if (password)
1180 {
1181 int retval = pamUpdatePassword(username, *password);
1182
1183 if (retval == PAM_USER_UNKNOWN)
1184 {
1185 messages::resourceNotFound(asyncResp->res, "ManagerAccount",
1186 username);
1187 }
1188 else if (retval == PAM_AUTHTOK_ERR)
1189 {
1190 // If password is invalid
1191 messages::propertyValueFormatError(asyncResp->res,
1192 *password, "Password");
1193 BMCWEB_LOG_ERROR << "pamUpdatePassword Failed";
1194 }
1195 else if (retval != PAM_SUCCESS)
1196 {
1197 messages::internalError(asyncResp->res);
1198 return;
1199 }
1200 else
1201 {
1202 messages::success(asyncResp->res);
1203 }
1204 }
1205
1206 if (enabled)
1207 {
1208 crow::connections::systemBus->async_method_call(
1209 [asyncResp](const boost::system::error_code ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001210 if (ec)
Ed Tanous04ae99e2018-09-20 15:54:36 -07001211 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001212 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
Ayushi Smriti599c71d2019-08-23 17:43:18 +00001213 messages::internalError(asyncResp->res);
Ed Tanous04ae99e2018-09-20 15:54:36 -07001214 return;
1215 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001216 messages::success(asyncResp->res);
1217 return;
Ed Tanous618c14b2022-06-30 17:44:25 -07001218 },
1219 "xyz.openbmc_project.User.Manager", dbusObjectPath,
1220 "org.freedesktop.DBus.Properties", "Set",
1221 "xyz.openbmc_project.User.Attributes", "UserEnabled",
1222 dbus::utility::DbusVariantType{*enabled});
Ed Tanous002d39b2022-05-31 08:59:27 -07001223 }
Ed Tanous04ae99e2018-09-20 15:54:36 -07001224
Ed Tanous618c14b2022-06-30 17:44:25 -07001225 if (roleId)
1226 {
1227 std::string priv = getPrivilegeFromRoleId(*roleId);
1228 if (priv.empty())
1229 {
1230 messages::propertyValueNotInList(asyncResp->res, *roleId,
1231 "RoleId");
1232 return;
1233 }
1234
1235 crow::connections::systemBus->async_method_call(
1236 [asyncResp](const boost::system::error_code ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001237 if (ec)
Ed Tanous04ae99e2018-09-20 15:54:36 -07001238 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001239 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
1240 messages::internalError(asyncResp->res);
Ed Tanous6c51eab2021-06-03 12:30:29 -07001241 return;
1242 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001243 messages::success(asyncResp->res);
Ed Tanous618c14b2022-06-30 17:44:25 -07001244 },
1245 "xyz.openbmc_project.User.Manager", dbusObjectPath,
1246 "org.freedesktop.DBus.Properties", "Set",
1247 "xyz.openbmc_project.User.Attributes", "UserPrivilege",
1248 dbus::utility::DbusVariantType{priv});
Ed Tanous6c51eab2021-06-03 12:30:29 -07001249 }
1250
Ed Tanous618c14b2022-06-30 17:44:25 -07001251 if (locked)
1252 {
1253 // admin can unlock the account which is locked by
1254 // successive authentication failures but admin should
1255 // not be allowed to lock an account.
1256 if (*locked)
1257 {
1258 messages::propertyValueNotInList(asyncResp->res, "true",
1259 "Locked");
1260 return;
1261 }
1262
1263 crow::connections::systemBus->async_method_call(
1264 [asyncResp](const boost::system::error_code ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001265 if (ec)
Ed Tanous6c51eab2021-06-03 12:30:29 -07001266 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001267 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
1268 messages::internalError(asyncResp->res);
Ed Tanous04ae99e2018-09-20 15:54:36 -07001269 return;
1270 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001271 messages::success(asyncResp->res);
1272 return;
Ed Tanous618c14b2022-06-30 17:44:25 -07001273 },
1274 "xyz.openbmc_project.User.Manager", dbusObjectPath,
1275 "org.freedesktop.DBus.Properties", "Set",
1276 "xyz.openbmc_project.User.Attributes",
1277 "UserLockedForFailedAttempt",
1278 dbus::utility::DbusVariantType{*locked});
1279 }
Ed Tanous6c51eab2021-06-03 12:30:29 -07001280 });
1281}
Ed Tanousb9b2e0b2018-09-13 13:47:50 -07001282
Ed Tanous4c7d4d32022-07-07 15:29:35 -07001283inline void handleAccountServiceHead(
1284 App& app, const crow::Request& req,
1285 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Ed Tanous1ef4c342022-05-12 16:12:36 -07001286{
Ed Tanous4c7d4d32022-07-07 15:29:35 -07001287
Ed Tanous1ef4c342022-05-12 16:12:36 -07001288 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1289 {
1290 return;
1291 }
Ed Tanous4c7d4d32022-07-07 15:29:35 -07001292 asyncResp->res.addHeader(
1293 boost::beast::http::field::link,
1294 "</redfish/v1/JsonSchemas/AccountService/AccountService.json>; rel=describedby");
1295}
1296
1297inline void
1298 handleAccountServiceGet(App& app, const crow::Request& req,
1299 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1300{
1301 handleAccountServiceHead(app, req, asyncResp);
Ed Tanous1ef4c342022-05-12 16:12:36 -07001302 const persistent_data::AuthConfigMethods& authMethodsConfig =
1303 persistent_data::SessionStore::getInstance().getAuthMethodsConfig();
1304
1305 nlohmann::json& json = asyncResp->res.jsonValue;
1306 json["@odata.id"] = "/redfish/v1/AccountService";
1307 json["@odata.type"] = "#AccountService."
1308 "v1_10_0.AccountService";
1309 json["Id"] = "AccountService";
1310 json["Name"] = "Account Service";
1311 json["Description"] = "Account Service";
1312 json["ServiceEnabled"] = true;
1313 json["MaxPasswordLength"] = 20;
1314 json["Accounts"]["@odata.id"] = "/redfish/v1/AccountService/Accounts";
1315 json["Roles"]["@odata.id"] = "/redfish/v1/AccountService/Roles";
1316 json["Oem"]["OpenBMC"]["@odata.type"] =
1317 "#OemAccountService.v1_0_0.AccountService";
1318 json["Oem"]["OpenBMC"]["@odata.id"] =
1319 "/redfish/v1/AccountService#/Oem/OpenBMC";
1320 json["Oem"]["OpenBMC"]["AuthMethods"]["BasicAuth"] =
1321 authMethodsConfig.basic;
1322 json["Oem"]["OpenBMC"]["AuthMethods"]["SessionToken"] =
1323 authMethodsConfig.sessionToken;
1324 json["Oem"]["OpenBMC"]["AuthMethods"]["XToken"] = authMethodsConfig.xtoken;
1325 json["Oem"]["OpenBMC"]["AuthMethods"]["Cookie"] = authMethodsConfig.cookie;
1326 json["Oem"]["OpenBMC"]["AuthMethods"]["TLS"] = authMethodsConfig.tls;
1327
1328 // /redfish/v1/AccountService/LDAP/Certificates is something only
1329 // ConfigureManager can access then only display when the user has
1330 // permissions ConfigureManager
1331 Privileges effectiveUserPrivileges =
1332 redfish::getUserPrivileges(req.userRole);
1333
1334 if (isOperationAllowedWithPrivileges({{"ConfigureManager"}},
1335 effectiveUserPrivileges))
1336 {
1337 asyncResp->res.jsonValue["LDAP"]["Certificates"]["@odata.id"] =
1338 "/redfish/v1/AccountService/LDAP/Certificates";
1339 }
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001340 sdbusplus::asio::getAllProperties(
1341 *crow::connections::systemBus, "xyz.openbmc_project.User.Manager",
1342 "/xyz/openbmc_project/user", "xyz.openbmc_project.User.AccountPolicy",
Ed Tanous1ef4c342022-05-12 16:12:36 -07001343 [asyncResp](const boost::system::error_code ec,
1344 const dbus::utility::DBusPropertiesMap& propertiesList) {
1345 if (ec)
1346 {
1347 messages::internalError(asyncResp->res);
1348 return;
1349 }
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001350
Ed Tanous1ef4c342022-05-12 16:12:36 -07001351 BMCWEB_LOG_DEBUG << "Got " << propertiesList.size()
1352 << "properties for AccountService";
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001353
1354 const uint8_t* minPasswordLength = nullptr;
1355 const uint32_t* accountUnlockTimeout = nullptr;
1356 const uint16_t* maxLoginAttemptBeforeLockout = nullptr;
1357
1358 const bool success = sdbusplus::unpackPropertiesNoThrow(
1359 dbus_utils::UnpackErrorPrinter(), propertiesList,
1360 "MinPasswordLength", minPasswordLength, "AccountUnlockTimeout",
1361 accountUnlockTimeout, "MaxLoginAttemptBeforeLockout",
1362 maxLoginAttemptBeforeLockout);
1363
1364 if (!success)
Ed Tanous1ef4c342022-05-12 16:12:36 -07001365 {
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001366 messages::internalError(asyncResp->res);
1367 return;
Ed Tanous1ef4c342022-05-12 16:12:36 -07001368 }
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001369
1370 if (minPasswordLength != nullptr)
1371 {
1372 asyncResp->res.jsonValue["MinPasswordLength"] = *minPasswordLength;
1373 }
1374
1375 if (accountUnlockTimeout != nullptr)
1376 {
1377 asyncResp->res.jsonValue["AccountLockoutDuration"] =
1378 *accountUnlockTimeout;
1379 }
1380
1381 if (maxLoginAttemptBeforeLockout != nullptr)
1382 {
1383 asyncResp->res.jsonValue["AccountLockoutThreshold"] =
1384 *maxLoginAttemptBeforeLockout;
1385 }
1386 });
Ed Tanous1ef4c342022-05-12 16:12:36 -07001387
Ed Tanous02cad962022-06-30 16:50:15 -07001388 auto callback = [asyncResp](bool success, const LDAPConfigData& confData,
Ed Tanous1ef4c342022-05-12 16:12:36 -07001389 const std::string& ldapType) {
1390 if (!success)
1391 {
1392 return;
1393 }
1394 parseLDAPConfigData(asyncResp->res.jsonValue, confData, ldapType);
1395 };
1396
1397 getLDAPConfigData("LDAP", callback);
1398 getLDAPConfigData("ActiveDirectory", callback);
1399}
1400
1401inline void handleAccountServicePatch(
1402 App& app, const crow::Request& req,
1403 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1404{
1405 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1406 {
1407 return;
1408 }
1409 std::optional<uint32_t> unlockTimeout;
1410 std::optional<uint16_t> lockoutThreshold;
1411 std::optional<uint8_t> minPasswordLength;
1412 std::optional<uint16_t> maxPasswordLength;
1413 std::optional<nlohmann::json> ldapObject;
1414 std::optional<nlohmann::json> activeDirectoryObject;
1415 std::optional<nlohmann::json> oemObject;
1416
1417 if (!json_util::readJsonPatch(
1418 req, asyncResp->res, "AccountLockoutDuration", unlockTimeout,
1419 "AccountLockoutThreshold", lockoutThreshold, "MaxPasswordLength",
1420 maxPasswordLength, "MinPasswordLength", minPasswordLength, "LDAP",
1421 ldapObject, "ActiveDirectory", activeDirectoryObject, "Oem",
1422 oemObject))
1423 {
1424 return;
1425 }
1426
1427 if (minPasswordLength)
1428 {
1429 crow::connections::systemBus->async_method_call(
1430 [asyncResp](const boost::system::error_code ec) {
1431 if (ec)
1432 {
1433 messages::internalError(asyncResp->res);
1434 return;
1435 }
1436 messages::success(asyncResp->res);
1437 },
1438 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
1439 "org.freedesktop.DBus.Properties", "Set",
1440 "xyz.openbmc_project.User.AccountPolicy", "MinPasswordLength",
1441 dbus::utility::DbusVariantType(*minPasswordLength));
1442 }
1443
1444 if (maxPasswordLength)
1445 {
1446 messages::propertyNotWritable(asyncResp->res, "MaxPasswordLength");
1447 }
1448
1449 if (ldapObject)
1450 {
1451 handleLDAPPatch(*ldapObject, asyncResp, "LDAP");
1452 }
1453
1454 if (std::optional<nlohmann::json> oemOpenBMCObject;
1455 oemObject && json_util::readJson(*oemObject, asyncResp->res, "OpenBMC",
1456 oemOpenBMCObject))
1457 {
1458 if (std::optional<nlohmann::json> authMethodsObject;
1459 oemOpenBMCObject &&
1460 json_util::readJson(*oemOpenBMCObject, asyncResp->res,
1461 "AuthMethods", authMethodsObject))
1462 {
1463 if (authMethodsObject)
1464 {
1465 handleAuthMethodsPatch(*authMethodsObject, asyncResp);
1466 }
1467 }
1468 }
1469
1470 if (activeDirectoryObject)
1471 {
1472 handleLDAPPatch(*activeDirectoryObject, asyncResp, "ActiveDirectory");
1473 }
1474
1475 if (unlockTimeout)
1476 {
1477 crow::connections::systemBus->async_method_call(
1478 [asyncResp](const boost::system::error_code ec) {
1479 if (ec)
1480 {
1481 messages::internalError(asyncResp->res);
1482 return;
1483 }
1484 messages::success(asyncResp->res);
1485 },
1486 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
1487 "org.freedesktop.DBus.Properties", "Set",
1488 "xyz.openbmc_project.User.AccountPolicy", "AccountUnlockTimeout",
1489 dbus::utility::DbusVariantType(*unlockTimeout));
1490 }
1491 if (lockoutThreshold)
1492 {
1493 crow::connections::systemBus->async_method_call(
1494 [asyncResp](const boost::system::error_code ec) {
1495 if (ec)
1496 {
1497 messages::internalError(asyncResp->res);
1498 return;
1499 }
1500 messages::success(asyncResp->res);
1501 },
1502 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
1503 "org.freedesktop.DBus.Properties", "Set",
1504 "xyz.openbmc_project.User.AccountPolicy",
1505 "MaxLoginAttemptBeforeLockout",
1506 dbus::utility::DbusVariantType(*lockoutThreshold));
1507 }
1508}
1509
Ed Tanous4c7d4d32022-07-07 15:29:35 -07001510inline void handleAccountCollectionHead(
Ed Tanous1ef4c342022-05-12 16:12:36 -07001511 App& app, const crow::Request& req,
1512 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1513{
Ed Tanous4c7d4d32022-07-07 15:29:35 -07001514
Ed Tanous1ef4c342022-05-12 16:12:36 -07001515 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1516 {
1517 return;
1518 }
Ed Tanous4c7d4d32022-07-07 15:29:35 -07001519 asyncResp->res.addHeader(
1520 boost::beast::http::field::link,
1521 "</redfish/v1/JsonSchemas/ManagerAccountCollection.json>; rel=describedby");
1522}
1523
1524inline void handleAccountCollectionGet(
1525 App& app, const crow::Request& req,
1526 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1527{
1528 handleAccountCollectionHead(app, req, asyncResp);
Ed Tanous1ef4c342022-05-12 16:12:36 -07001529
1530 asyncResp->res.jsonValue["@odata.id"] =
1531 "/redfish/v1/AccountService/Accounts";
1532 asyncResp->res.jsonValue["@odata.type"] = "#ManagerAccountCollection."
1533 "ManagerAccountCollection";
1534 asyncResp->res.jsonValue["Name"] = "Accounts Collection";
1535 asyncResp->res.jsonValue["Description"] = "BMC User Accounts";
1536
1537 Privileges effectiveUserPrivileges =
1538 redfish::getUserPrivileges(req.userRole);
1539
1540 std::string thisUser;
1541 if (req.session)
1542 {
1543 thisUser = req.session->username;
1544 }
1545 crow::connections::systemBus->async_method_call(
1546 [asyncResp, thisUser, effectiveUserPrivileges](
1547 const boost::system::error_code ec,
1548 const dbus::utility::ManagedObjectType& users) {
1549 if (ec)
1550 {
1551 messages::internalError(asyncResp->res);
1552 return;
1553 }
1554
1555 bool userCanSeeAllAccounts =
1556 effectiveUserPrivileges.isSupersetOf({"ConfigureUsers"});
1557
1558 bool userCanSeeSelf =
1559 effectiveUserPrivileges.isSupersetOf({"ConfigureSelf"});
1560
1561 nlohmann::json& memberArray = asyncResp->res.jsonValue["Members"];
1562 memberArray = nlohmann::json::array();
1563
1564 for (const auto& userpath : users)
1565 {
1566 std::string user = userpath.first.filename();
1567 if (user.empty())
1568 {
1569 messages::internalError(asyncResp->res);
1570 BMCWEB_LOG_ERROR << "Invalid firmware ID";
1571
1572 return;
1573 }
1574
1575 // As clarified by Redfish here:
1576 // https://redfishforum.com/thread/281/manageraccountcollection-change-allows-account-enumeration
1577 // Users without ConfigureUsers, only see their own
1578 // account. Users with ConfigureUsers, see all
1579 // accounts.
1580 if (userCanSeeAllAccounts || (thisUser == user && userCanSeeSelf))
1581 {
1582 nlohmann::json::object_t member;
1583 member["@odata.id"] =
1584 "/redfish/v1/AccountService/Accounts/" + user;
1585 memberArray.push_back(std::move(member));
1586 }
1587 }
1588 asyncResp->res.jsonValue["Members@odata.count"] = memberArray.size();
1589 },
1590 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
1591 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
1592}
1593
1594inline void handleAccountCollectionPost(
1595 App& app, const crow::Request& req,
1596 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1597{
1598 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1599 {
1600 return;
1601 }
1602 std::string username;
1603 std::string password;
1604 std::optional<std::string> roleId("User");
1605 std::optional<bool> enabled = true;
1606 if (!json_util::readJsonPatch(req, asyncResp->res, "UserName", username,
1607 "Password", password, "RoleId", roleId,
1608 "Enabled", enabled))
1609 {
1610 return;
1611 }
1612
1613 std::string priv = getPrivilegeFromRoleId(*roleId);
1614 if (priv.empty())
1615 {
1616 messages::propertyValueNotInList(asyncResp->res, *roleId, "RoleId");
1617 return;
1618 }
Asmitha Karunanithi239adf82022-03-25 02:59:03 -05001619 roleId = priv;
Ed Tanous1ef4c342022-05-12 16:12:36 -07001620
1621 // Reading AllGroups property
1622 sdbusplus::asio::getProperty<std::vector<std::string>>(
1623 *crow::connections::systemBus, "xyz.openbmc_project.User.Manager",
1624 "/xyz/openbmc_project/user", "xyz.openbmc_project.User.Manager",
1625 "AllGroups",
1626 [asyncResp, username, password{std::move(password)}, roleId,
1627 enabled](const boost::system::error_code ec,
1628 const std::vector<std::string>& allGroupsList) {
1629 if (ec)
1630 {
1631 BMCWEB_LOG_DEBUG << "ERROR with async_method_call";
1632 messages::internalError(asyncResp->res);
1633 return;
1634 }
1635
1636 if (allGroupsList.empty())
1637 {
1638 messages::internalError(asyncResp->res);
1639 return;
1640 }
1641
1642 crow::connections::systemBus->async_method_call(
1643 [asyncResp, username, password](const boost::system::error_code ec2,
Patrick Williams59d494e2022-07-22 19:26:55 -05001644 sdbusplus::message_t& m) {
Ed Tanous1ef4c342022-05-12 16:12:36 -07001645 if (ec2)
1646 {
1647 userErrorMessageHandler(m.get_error(), asyncResp, username, "");
1648 return;
1649 }
1650
1651 if (pamUpdatePassword(username, password) != PAM_SUCCESS)
1652 {
1653 // At this point we have a user that's been
1654 // created, but the password set
1655 // failed.Something is wrong, so delete the user
1656 // that we've already created
1657 sdbusplus::message::object_path tempObjPath(rootUserDbusPath);
1658 tempObjPath /= username;
1659 const std::string userPath(tempObjPath);
1660
1661 crow::connections::systemBus->async_method_call(
1662 [asyncResp, password](const boost::system::error_code ec3) {
1663 if (ec3)
1664 {
1665 messages::internalError(asyncResp->res);
1666 return;
1667 }
1668
1669 // If password is invalid
1670 messages::propertyValueFormatError(asyncResp->res, password,
1671 "Password");
1672 },
1673 "xyz.openbmc_project.User.Manager", userPath,
1674 "xyz.openbmc_project.Object.Delete", "Delete");
1675
1676 BMCWEB_LOG_ERROR << "pamUpdatePassword Failed";
1677 return;
1678 }
1679
1680 messages::created(asyncResp->res);
1681 asyncResp->res.addHeader(
1682 "Location", "/redfish/v1/AccountService/Accounts/" + username);
1683 },
1684 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
1685 "xyz.openbmc_project.User.Manager", "CreateUser", username,
1686 allGroupsList, *roleId, *enabled);
1687 });
1688}
1689
1690inline void
Ed Tanous4c7d4d32022-07-07 15:29:35 -07001691 handleAccountHead(App& app, const crow::Request& req,
1692 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1693 const std::string& /*accountName*/)
Ed Tanous1ef4c342022-05-12 16:12:36 -07001694{
Ed Tanous4c7d4d32022-07-07 15:29:35 -07001695
Ed Tanous1ef4c342022-05-12 16:12:36 -07001696 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1697 {
1698 return;
1699 }
Ed Tanous4c7d4d32022-07-07 15:29:35 -07001700 asyncResp->res.addHeader(
1701 boost::beast::http::field::link,
1702 "</redfish/v1/JsonSchemas/ManagerAccount/ManagerAccount.json>; rel=describedby");
1703}
1704inline void
1705 handleAccountGet(App& app, const crow::Request& req,
1706 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1707 const std::string& accountName)
1708{
1709 handleAccountHead(app, req, asyncResp, accountName);
Ed Tanous1ef4c342022-05-12 16:12:36 -07001710#ifdef BMCWEB_INSECURE_DISABLE_AUTHENTICATION
1711 // If authentication is disabled, there are no user accounts
Jiaqing Zhaod8a5d5d2022-08-05 16:21:51 +08001712 messages::resourceNotFound(asyncResp->res, "ManagerAccount", accountName);
Ed Tanous1ef4c342022-05-12 16:12:36 -07001713 return;
1714
1715#endif // BMCWEB_INSECURE_DISABLE_AUTHENTICATION
1716 if (req.session == nullptr)
1717 {
1718 messages::internalError(asyncResp->res);
1719 return;
1720 }
1721 if (req.session->username != accountName)
1722 {
1723 // At this point we've determined that the user is trying to
1724 // modify a user that isn't them. We need to verify that they
1725 // have permissions to modify other users, so re-run the auth
1726 // check with the same permissions, minus ConfigureSelf.
1727 Privileges effectiveUserPrivileges =
1728 redfish::getUserPrivileges(req.userRole);
1729 Privileges requiredPermissionsToChangeNonSelf = {"ConfigureUsers",
1730 "ConfigureManager"};
1731 if (!effectiveUserPrivileges.isSupersetOf(
1732 requiredPermissionsToChangeNonSelf))
1733 {
1734 BMCWEB_LOG_DEBUG << "GET Account denied access";
1735 messages::insufficientPrivilege(asyncResp->res);
1736 return;
1737 }
1738 }
1739
1740 crow::connections::systemBus->async_method_call(
1741 [asyncResp,
1742 accountName](const boost::system::error_code ec,
1743 const dbus::utility::ManagedObjectType& users) {
1744 if (ec)
1745 {
1746 messages::internalError(asyncResp->res);
1747 return;
1748 }
1749 const auto userIt = std::find_if(
1750 users.begin(), users.end(),
1751 [accountName](
1752 const std::pair<sdbusplus::message::object_path,
1753 dbus::utility::DBusInteracesMap>& user) {
1754 return accountName == user.first.filename();
1755 });
1756
1757 if (userIt == users.end())
1758 {
1759 messages::resourceNotFound(asyncResp->res, "ManagerAccount",
1760 accountName);
1761 return;
1762 }
1763
1764 asyncResp->res.jsonValue["@odata.type"] =
1765 "#ManagerAccount.v1_4_0.ManagerAccount";
1766 asyncResp->res.jsonValue["Name"] = "User Account";
1767 asyncResp->res.jsonValue["Description"] = "User Account";
1768 asyncResp->res.jsonValue["Password"] = nullptr;
Ed Tanous1ef4c342022-05-12 16:12:36 -07001769
1770 for (const auto& interface : userIt->second)
1771 {
1772 if (interface.first == "xyz.openbmc_project.User.Attributes")
1773 {
1774 for (const auto& property : interface.second)
1775 {
1776 if (property.first == "UserEnabled")
1777 {
1778 const bool* userEnabled =
1779 std::get_if<bool>(&property.second);
1780 if (userEnabled == nullptr)
1781 {
1782 BMCWEB_LOG_ERROR << "UserEnabled wasn't a bool";
1783 messages::internalError(asyncResp->res);
1784 return;
1785 }
1786 asyncResp->res.jsonValue["Enabled"] = *userEnabled;
1787 }
1788 else if (property.first == "UserLockedForFailedAttempt")
1789 {
1790 const bool* userLocked =
1791 std::get_if<bool>(&property.second);
1792 if (userLocked == nullptr)
1793 {
1794 BMCWEB_LOG_ERROR << "UserLockedForF"
1795 "ailedAttempt "
1796 "wasn't a bool";
1797 messages::internalError(asyncResp->res);
1798 return;
1799 }
1800 asyncResp->res.jsonValue["Locked"] = *userLocked;
1801 asyncResp->res
1802 .jsonValue["Locked@Redfish.AllowableValues"] = {
1803 "false"}; // can only unlock accounts
1804 }
1805 else if (property.first == "UserPrivilege")
1806 {
1807 const std::string* userPrivPtr =
1808 std::get_if<std::string>(&property.second);
1809 if (userPrivPtr == nullptr)
1810 {
1811 BMCWEB_LOG_ERROR << "UserPrivilege wasn't a "
1812 "string";
1813 messages::internalError(asyncResp->res);
1814 return;
1815 }
1816 std::string role = getRoleIdFromPrivilege(*userPrivPtr);
1817 if (role.empty())
1818 {
1819 BMCWEB_LOG_ERROR << "Invalid user role";
1820 messages::internalError(asyncResp->res);
1821 return;
1822 }
1823 asyncResp->res.jsonValue["RoleId"] = role;
1824
1825 nlohmann::json& roleEntry =
1826 asyncResp->res.jsonValue["Links"]["Role"];
1827 roleEntry["@odata.id"] =
1828 "/redfish/v1/AccountService/Roles/" + role;
1829 }
1830 else if (property.first == "UserPasswordExpired")
1831 {
1832 const bool* userPasswordExpired =
1833 std::get_if<bool>(&property.second);
1834 if (userPasswordExpired == nullptr)
1835 {
1836 BMCWEB_LOG_ERROR
1837 << "UserPasswordExpired wasn't a bool";
1838 messages::internalError(asyncResp->res);
1839 return;
1840 }
1841 asyncResp->res.jsonValue["PasswordChangeRequired"] =
1842 *userPasswordExpired;
1843 }
Abhishek Patelc7229812022-02-01 10:07:15 -06001844 else if (property.first == "UserGroups")
1845 {
1846 const std::vector<std::string>* userGroups =
1847 std::get_if<std::vector<std::string>>(
1848 &property.second);
1849 if (userGroups == nullptr)
1850 {
1851 BMCWEB_LOG_ERROR
1852 << "userGroups wasn't a string vector";
1853 messages::internalError(asyncResp->res);
1854 return;
1855 }
1856 if (!translateUserGroup(*userGroups, asyncResp->res))
1857 {
1858 BMCWEB_LOG_ERROR << "userGroups mapping failed";
1859 messages::internalError(asyncResp->res);
1860 return;
1861 }
1862 }
Ed Tanous1ef4c342022-05-12 16:12:36 -07001863 }
1864 }
1865 }
1866
1867 asyncResp->res.jsonValue["@odata.id"] =
1868 "/redfish/v1/AccountService/Accounts/" + accountName;
1869 asyncResp->res.jsonValue["Id"] = accountName;
1870 asyncResp->res.jsonValue["UserName"] = accountName;
1871 },
1872 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
1873 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
1874}
1875
1876inline void
1877 handleAccounttDelete(App& app, const crow::Request& req,
1878 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1879 const std::string& username)
1880{
1881 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1882 {
1883 return;
1884 }
1885
1886#ifdef BMCWEB_INSECURE_DISABLE_AUTHENTICATION
1887 // If authentication is disabled, there are no user accounts
Jiaqing Zhaod8a5d5d2022-08-05 16:21:51 +08001888 messages::resourceNotFound(asyncResp->res, "ManagerAccount", username);
Ed Tanous1ef4c342022-05-12 16:12:36 -07001889 return;
1890
1891#endif // BMCWEB_INSECURE_DISABLE_AUTHENTICATION
1892 sdbusplus::message::object_path tempObjPath(rootUserDbusPath);
1893 tempObjPath /= username;
1894 const std::string userPath(tempObjPath);
1895
1896 crow::connections::systemBus->async_method_call(
1897 [asyncResp, username](const boost::system::error_code ec) {
1898 if (ec)
1899 {
Jiaqing Zhaod8a5d5d2022-08-05 16:21:51 +08001900 messages::resourceNotFound(asyncResp->res, "ManagerAccount",
Ed Tanous1ef4c342022-05-12 16:12:36 -07001901 username);
1902 return;
1903 }
1904
1905 messages::accountRemoved(asyncResp->res);
1906 },
1907 "xyz.openbmc_project.User.Manager", userPath,
1908 "xyz.openbmc_project.Object.Delete", "Delete");
1909}
1910
1911inline void
1912 handleAccountPatch(App& app, const crow::Request& req,
1913 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1914 const std::string& username)
1915{
1916 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1917 {
1918 return;
1919 }
1920#ifdef BMCWEB_INSECURE_DISABLE_AUTHENTICATION
1921 // If authentication is disabled, there are no user accounts
Jiaqing Zhaod8a5d5d2022-08-05 16:21:51 +08001922 messages::resourceNotFound(asyncResp->res, "ManagerAccount", username);
Ed Tanous1ef4c342022-05-12 16:12:36 -07001923 return;
1924
1925#endif // BMCWEB_INSECURE_DISABLE_AUTHENTICATION
1926 std::optional<std::string> newUserName;
1927 std::optional<std::string> password;
1928 std::optional<bool> enabled;
1929 std::optional<std::string> roleId;
1930 std::optional<bool> locked;
1931
1932 if (req.session == nullptr)
1933 {
1934 messages::internalError(asyncResp->res);
1935 return;
1936 }
1937
1938 Privileges effectiveUserPrivileges =
1939 redfish::getUserPrivileges(req.userRole);
1940 Privileges configureUsers = {"ConfigureUsers"};
1941 bool userHasConfigureUsers =
1942 effectiveUserPrivileges.isSupersetOf(configureUsers);
1943 if (userHasConfigureUsers)
1944 {
1945 // Users with ConfigureUsers can modify for all users
1946 if (!json_util::readJsonPatch(req, asyncResp->res, "UserName",
1947 newUserName, "Password", password,
1948 "RoleId", roleId, "Enabled", enabled,
1949 "Locked", locked))
1950 {
1951 return;
1952 }
1953 }
1954 else
1955 {
1956 // ConfigureSelf accounts can only modify their own account
1957 if (username != req.session->username)
1958 {
1959 messages::insufficientPrivilege(asyncResp->res);
1960 return;
1961 }
1962
1963 // ConfigureSelf accounts can only modify their password
1964 if (!json_util::readJsonPatch(req, asyncResp->res, "Password",
1965 password))
1966 {
1967 return;
1968 }
1969 }
1970
1971 // if user name is not provided in the patch method or if it
1972 // matches the user name in the URI, then we are treating it as
1973 // updating user properties other then username. If username
1974 // provided doesn't match the URI, then we are treating this as
1975 // user rename request.
1976 if (!newUserName || (newUserName.value() == username))
1977 {
1978 updateUserProperties(asyncResp, username, password, enabled, roleId,
1979 locked);
1980 return;
1981 }
1982 crow::connections::systemBus->async_method_call(
1983 [asyncResp, username, password(std::move(password)),
1984 roleId(std::move(roleId)), enabled, newUser{std::string(*newUserName)},
Patrick Williams59d494e2022-07-22 19:26:55 -05001985 locked](const boost::system::error_code ec, sdbusplus::message_t& m) {
Ed Tanous1ef4c342022-05-12 16:12:36 -07001986 if (ec)
1987 {
1988 userErrorMessageHandler(m.get_error(), asyncResp, newUser,
1989 username);
1990 return;
1991 }
1992
1993 updateUserProperties(asyncResp, newUser, password, enabled, roleId,
1994 locked);
1995 },
1996 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
1997 "xyz.openbmc_project.User.Manager", "RenameUser", username,
1998 *newUserName);
1999}
2000
Ed Tanous6c51eab2021-06-03 12:30:29 -07002001inline void requestAccountServiceRoutes(App& app)
Ed Tanousb9b2e0b2018-09-13 13:47:50 -07002002{
Ed Tanousb9b2e0b2018-09-13 13:47:50 -07002003
Ed Tanous6c51eab2021-06-03 12:30:29 -07002004 BMCWEB_ROUTE(app, "/redfish/v1/AccountService/")
Ed Tanous4c7d4d32022-07-07 15:29:35 -07002005 .privileges(redfish::privileges::headAccountService)
2006 .methods(boost::beast::http::verb::head)(
2007 std::bind_front(handleAccountServiceHead, std::ref(app)));
2008
2009 BMCWEB_ROUTE(app, "/redfish/v1/AccountService/")
Ed Tanoused398212021-06-09 17:05:54 -07002010 .privileges(redfish::privileges::getAccountService)
Ed Tanous002d39b2022-05-31 08:59:27 -07002011 .methods(boost::beast::http::verb::get)(
Ed Tanous1ef4c342022-05-12 16:12:36 -07002012 std::bind_front(handleAccountServiceGet, std::ref(app)));
Ed Tanous6c51eab2021-06-03 12:30:29 -07002013
Ed Tanousf5ffd802021-07-19 10:55:33 -07002014 BMCWEB_ROUTE(app, "/redfish/v1/AccountService/")
Gunnar Mills1ec43ee2022-01-04 15:39:52 -06002015 .privileges(redfish::privileges::patchAccountService)
Ed Tanousf5ffd802021-07-19 10:55:33 -07002016 .methods(boost::beast::http::verb::patch)(
Ed Tanous1ef4c342022-05-12 16:12:36 -07002017 std::bind_front(handleAccountServicePatch, std::ref(app)));
Ed Tanousf5ffd802021-07-19 10:55:33 -07002018
Ed Tanous6c51eab2021-06-03 12:30:29 -07002019 BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/")
Ed Tanous4c7d4d32022-07-07 15:29:35 -07002020 .privileges(redfish::privileges::headManagerAccountCollection)
2021 .methods(boost::beast::http::verb::head)(
2022 std::bind_front(handleAccountCollectionHead, std::ref(app)));
2023
2024 BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/")
Ed Tanoused398212021-06-09 17:05:54 -07002025 .privileges(redfish::privileges::getManagerAccountCollection)
Ed Tanous6c51eab2021-06-03 12:30:29 -07002026 .methods(boost::beast::http::verb::get)(
Ed Tanous1ef4c342022-05-12 16:12:36 -07002027 std::bind_front(handleAccountCollectionGet, std::ref(app)));
Ed Tanous06e086d2018-09-19 17:19:52 -07002028
Ed Tanous6c51eab2021-06-03 12:30:29 -07002029 BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/")
Ed Tanoused398212021-06-09 17:05:54 -07002030 .privileges(redfish::privileges::postManagerAccountCollection)
Ed Tanous002d39b2022-05-31 08:59:27 -07002031 .methods(boost::beast::http::verb::post)(
Ed Tanous1ef4c342022-05-12 16:12:36 -07002032 std::bind_front(handleAccountCollectionPost, std::ref(app)));
Ed Tanous002d39b2022-05-31 08:59:27 -07002033
2034 BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/<str>/")
Ed Tanous4c7d4d32022-07-07 15:29:35 -07002035 .privileges(redfish::privileges::headManagerAccount)
2036 .methods(boost::beast::http::verb::head)(
2037 std::bind_front(handleAccountHead, std::ref(app)));
2038
2039 BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/<str>/")
Ed Tanous002d39b2022-05-31 08:59:27 -07002040 .privileges(redfish::privileges::getManagerAccount)
2041 .methods(boost::beast::http::verb::get)(
Ed Tanous1ef4c342022-05-12 16:12:36 -07002042 std::bind_front(handleAccountGet, std::ref(app)));
Ed Tanous6c51eab2021-06-03 12:30:29 -07002043
2044 BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002045 // TODO this privilege should be using the generated endpoints, but
2046 // because of the special handling of ConfigureSelf, it's not able to
2047 // yet
Ed Tanous6c51eab2021-06-03 12:30:29 -07002048 .privileges({{"ConfigureUsers"}, {"ConfigureSelf"}})
2049 .methods(boost::beast::http::verb::patch)(
Ed Tanous1ef4c342022-05-12 16:12:36 -07002050 std::bind_front(handleAccountPatch, std::ref(app)));
Ed Tanous6c51eab2021-06-03 12:30:29 -07002051
2052 BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002053 .privileges(redfish::privileges::deleteManagerAccount)
Ed Tanous6c51eab2021-06-03 12:30:29 -07002054 .methods(boost::beast::http::verb::delete_)(
Ed Tanous1ef4c342022-05-12 16:12:36 -07002055 std::bind_front(handleAccounttDelete, std::ref(app)));
Ed Tanous6c51eab2021-06-03 12:30:29 -07002056}
Lewanczyk, Dawid88d16c92018-02-02 14:51:09 +01002057
Ed Tanous1abe55e2018-09-05 08:30:59 -07002058} // namespace redfish