blob: abf255eb0005a281f1a6c2fd2b7ed8a1253a2e44 [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
Abhishek Patelc7229812022-02-01 10:07:15 -060032#include <optional>
33#include <string>
34#include <vector>
35
Ed Tanous1abe55e2018-09-05 08:30:59 -070036namespace redfish
37{
Lewanczyk, Dawid88d16c92018-02-02 14:51:09 +010038
Ed Tanous23a21a12020-07-25 04:45:05 +000039constexpr const char* ldapConfigObjectName =
Ratan Gupta6973a582018-12-13 18:25:44 +053040 "/xyz/openbmc_project/user/ldap/openldap";
Ed Tanous2c70f802020-09-28 14:29:23 -070041constexpr const char* adConfigObject =
Ratan Guptaab828d72019-04-22 14:18:33 +053042 "/xyz/openbmc_project/user/ldap/active_directory";
43
P Dheeraj Srujan Kumarb477fd42021-12-16 07:17:51 +053044constexpr const char* rootUserDbusPath = "/xyz/openbmc_project/user/";
Ratan Gupta6973a582018-12-13 18:25:44 +053045constexpr const char* ldapRootObject = "/xyz/openbmc_project/user/ldap";
46constexpr const char* ldapDbusService = "xyz.openbmc_project.Ldap.Config";
47constexpr const char* ldapConfigInterface =
48 "xyz.openbmc_project.User.Ldap.Config";
49constexpr const char* ldapCreateInterface =
50 "xyz.openbmc_project.User.Ldap.Create";
51constexpr const char* ldapEnableInterface = "xyz.openbmc_project.Object.Enable";
Ratan Gupta06785242019-07-26 22:30:16 +053052constexpr const char* ldapPrivMapperInterface =
53 "xyz.openbmc_project.User.PrivilegeMapper";
Ratan Gupta6973a582018-12-13 18:25:44 +053054constexpr const char* dbusObjManagerIntf = "org.freedesktop.DBus.ObjectManager";
55constexpr const char* propertyInterface = "org.freedesktop.DBus.Properties";
56constexpr const char* mapperBusName = "xyz.openbmc_project.ObjectMapper";
57constexpr const char* mapperObjectPath = "/xyz/openbmc_project/object_mapper";
58constexpr const char* mapperIntf = "xyz.openbmc_project.ObjectMapper";
59
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -060060struct LDAPRoleMapData
61{
62 std::string groupName;
63 std::string privilege;
64};
65
Ratan Gupta6973a582018-12-13 18:25:44 +053066struct LDAPConfigData
67{
68 std::string uri{};
69 std::string bindDN{};
70 std::string baseDN{};
71 std::string searchScope{};
72 std::string serverType{};
73 bool serviceEnabled = false;
74 std::string userNameAttribute{};
75 std::string groupAttribute{};
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -060076 std::vector<std::pair<std::string, LDAPRoleMapData>> groupRoleList;
Ratan Gupta6973a582018-12-13 18:25:44 +053077};
78
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -060079inline std::string getRoleIdFromPrivilege(std::string_view role)
AppaRao Puli84e12cb2018-10-11 01:28:15 +053080{
81 if (role == "priv-admin")
82 {
83 return "Administrator";
84 }
Ed Tanous3174e4d2020-10-07 11:41:22 -070085 if (role == "priv-user")
AppaRao Puli84e12cb2018-10-11 01:28:15 +053086 {
AppaRao Pulic80fee52019-10-16 14:49:36 +053087 return "ReadOnly";
AppaRao Puli84e12cb2018-10-11 01:28:15 +053088 }
Ed Tanous3174e4d2020-10-07 11:41:22 -070089 if (role == "priv-operator")
AppaRao Puli84e12cb2018-10-11 01:28:15 +053090 {
91 return "Operator";
92 }
93 return "";
94}
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -060095inline std::string getPrivilegeFromRoleId(std::string_view role)
AppaRao Puli84e12cb2018-10-11 01:28:15 +053096{
97 if (role == "Administrator")
98 {
99 return "priv-admin";
100 }
Ed Tanous3174e4d2020-10-07 11:41:22 -0700101 if (role == "ReadOnly")
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530102 {
103 return "priv-user";
104 }
Ed Tanous3174e4d2020-10-07 11:41:22 -0700105 if (role == "Operator")
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530106 {
107 return "priv-operator";
108 }
109 return "";
110}
Ed Tanousb9b2e0b2018-09-13 13:47:50 -0700111
Abhishek Patelc7229812022-02-01 10:07:15 -0600112/**
113 * @brief Maps user group names retrieved from D-Bus object to
114 * Account Types.
115 *
116 * @param[in] userGroups List of User groups
117 * @param[out] res AccountTypes populated
118 *
119 * @return true in case of success, false if UserGroups contains
120 * invalid group name(s).
121 */
122inline bool translateUserGroup(const std::vector<std::string>& userGroups,
123 crow::Response& res)
124{
125 std::vector<std::string> accountTypes;
126 for (const auto& userGroup : userGroups)
127 {
128 if (userGroup == "redfish")
129 {
130 accountTypes.emplace_back("Redfish");
131 accountTypes.emplace_back("WebUI");
132 }
133 else if (userGroup == "ipmi")
134 {
135 accountTypes.emplace_back("IPMI");
136 }
137 else if (userGroup == "ssh")
138 {
139 accountTypes.emplace_back("HostConsole");
140 accountTypes.emplace_back("ManagerConsole");
141 }
142 else if (userGroup == "web")
143 {
144 // 'web' is one of the valid groups in the UserGroups property of
145 // the user account in the D-Bus object. This group is currently not
146 // doing anything, and is considered to be equivalent to 'redfish'.
147 // 'redfish' user group is mapped to 'Redfish'and 'WebUI'
148 // AccountTypes, so do nothing here...
149 }
150 else
151 {
152 // Invalid user group name. Caller throws an excption.
153 return false;
154 }
155 }
156
157 res.jsonValue["AccountTypes"] = std::move(accountTypes);
158 return true;
159}
160
zhanghch058d1b46d2021-04-01 11:18:24 +0800161inline void userErrorMessageHandler(
162 const sd_bus_error* e, const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
163 const std::string& newUser, const std::string& username)
jayaprakash Mutyala66b5ca72019-08-07 20:26:37 +0000164{
jayaprakash Mutyala66b5ca72019-08-07 20:26:37 +0000165 if (e == nullptr)
166 {
167 messages::internalError(asyncResp->res);
168 return;
169 }
170
Manojkiran Eda055806b2020-11-03 09:36:28 +0530171 const char* errorMessage = e->name;
jayaprakash Mutyala66b5ca72019-08-07 20:26:37 +0000172 if (strcmp(errorMessage,
173 "xyz.openbmc_project.User.Common.Error.UserNameExists") == 0)
174 {
Jiaqing Zhaod8a5d5d2022-08-05 16:21:51 +0800175 messages::resourceAlreadyExists(asyncResp->res, "ManagerAccount",
jayaprakash Mutyala66b5ca72019-08-07 20:26:37 +0000176 "UserName", newUser);
177 }
178 else if (strcmp(errorMessage, "xyz.openbmc_project.User.Common.Error."
179 "UserNameDoesNotExist") == 0)
180 {
Jiaqing Zhaod8a5d5d2022-08-05 16:21:51 +0800181 messages::resourceNotFound(asyncResp->res, "ManagerAccount", username);
jayaprakash Mutyala66b5ca72019-08-07 20:26:37 +0000182 }
Ed Tanousd4d25792020-09-29 15:15:03 -0700183 else if ((strcmp(errorMessage,
184 "xyz.openbmc_project.Common.Error.InvalidArgument") ==
185 0) ||
George Liu0fda0f12021-11-16 10:06:17 +0800186 (strcmp(
187 errorMessage,
188 "xyz.openbmc_project.User.Common.Error.UserNameGroupFail") ==
189 0))
jayaprakash Mutyala66b5ca72019-08-07 20:26:37 +0000190 {
191 messages::propertyValueFormatError(asyncResp->res, newUser, "UserName");
192 }
193 else if (strcmp(errorMessage,
194 "xyz.openbmc_project.User.Common.Error.NoResource") == 0)
195 {
196 messages::createLimitReachedForResource(asyncResp->res);
197 }
jayaprakash Mutyala66b5ca72019-08-07 20:26:37 +0000198 else
199 {
200 messages::internalError(asyncResp->res);
201 }
jayaprakash Mutyala66b5ca72019-08-07 20:26:37 +0000202}
203
Ed Tanous81ce6092020-12-17 16:54:55 +0000204inline void parseLDAPConfigData(nlohmann::json& jsonResponse,
Ed Tanous23a21a12020-07-25 04:45:05 +0000205 const LDAPConfigData& confData,
206 const std::string& ldapType)
Ratan Gupta6973a582018-12-13 18:25:44 +0530207{
Ratan Guptaab828d72019-04-22 14:18:33 +0530208 std::string service =
209 (ldapType == "LDAP") ? "LDAPService" : "ActiveDirectoryService";
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600210
Ed Tanous14766872022-03-15 10:44:42 -0700211 nlohmann::json& ldap = jsonResponse[ldapType];
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600212
Ed Tanous14766872022-03-15 10:44:42 -0700213 ldap["ServiceEnabled"] = confData.serviceEnabled;
214 ldap["ServiceAddresses"] = nlohmann::json::array({confData.uri});
Ed Tanous0ec8b832022-03-14 14:56:47 -0700215 ldap["Authentication"]["AuthenticationType"] =
216 account_service::AuthenticationTypes::UsernameAndPassword;
Ed Tanous14766872022-03-15 10:44:42 -0700217 ldap["Authentication"]["Username"] = confData.bindDN;
218 ldap["Authentication"]["Password"] = nullptr;
219
220 ldap["LDAPService"]["SearchSettings"]["BaseDistinguishedNames"] =
221 nlohmann::json::array({confData.baseDN});
222 ldap["LDAPService"]["SearchSettings"]["UsernameAttribute"] =
223 confData.userNameAttribute;
224 ldap["LDAPService"]["SearchSettings"]["GroupsAttribute"] =
225 confData.groupAttribute;
226
227 nlohmann::json& roleMapArray = ldap["RemoteRoleMapping"];
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600228 roleMapArray = nlohmann::json::array();
Ed Tanous9eb808c2022-01-25 10:19:23 -0800229 for (const auto& obj : confData.groupRoleList)
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600230 {
231 BMCWEB_LOG_DEBUG << "Pushing the data groupName="
232 << obj.second.groupName << "\n";
Ed Tanous613dabe2022-07-09 11:17:36 -0700233
Ed Tanous613dabe2022-07-09 11:17:36 -0700234 nlohmann::json::object_t remoteGroup;
235 remoteGroup["RemoteGroup"] = obj.second.groupName;
Jorge Cisneros329f0342022-11-04 16:26:25 +0000236 remoteGroup["LocalRole"] = getRoleIdFromPrivilege(obj.second.privilege);
237 roleMapArray.emplace_back(std::move(remoteGroup));
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600238 }
Ratan Gupta6973a582018-12-13 18:25:44 +0530239}
240
241/**
Ratan Gupta06785242019-07-26 22:30:16 +0530242 * @brief validates given JSON input and then calls appropriate method to
243 * create, to delete or to set Rolemapping object based on the given input.
244 *
245 */
Ed Tanous23a21a12020-07-25 04:45:05 +0000246inline void handleRoleMapPatch(
zhanghch058d1b46d2021-04-01 11:18:24 +0800247 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ratan Gupta06785242019-07-26 22:30:16 +0530248 const std::vector<std::pair<std::string, LDAPRoleMapData>>& roleMapObjData,
Ed Tanousf23b7292020-10-15 09:41:17 -0700249 const std::string& serverType, const std::vector<nlohmann::json>& input)
Ratan Gupta06785242019-07-26 22:30:16 +0530250{
251 for (size_t index = 0; index < input.size(); index++)
252 {
Ed Tanousf23b7292020-10-15 09:41:17 -0700253 const nlohmann::json& thisJson = input[index];
Ratan Gupta06785242019-07-26 22:30:16 +0530254
255 if (thisJson.is_null())
256 {
257 // delete the existing object
258 if (index < roleMapObjData.size())
259 {
260 crow::connections::systemBus->async_method_call(
261 [asyncResp, roleMapObjData, serverType,
262 index](const boost::system::error_code ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700263 if (ec)
264 {
265 BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
266 messages::internalError(asyncResp->res);
267 return;
268 }
269 asyncResp->res
270 .jsonValue[serverType]["RemoteRoleMapping"][index] =
271 nullptr;
Ratan Gupta06785242019-07-26 22:30:16 +0530272 },
273 ldapDbusService, roleMapObjData[index].first,
274 "xyz.openbmc_project.Object.Delete", "Delete");
275 }
276 else
277 {
278 BMCWEB_LOG_ERROR << "Can't delete the object";
279 messages::propertyValueTypeError(
Ed Tanous71f52d92021-02-19 08:51:17 -0800280 asyncResp->res,
281 thisJson.dump(2, ' ', true,
282 nlohmann::json::error_handler_t::replace),
Ratan Gupta06785242019-07-26 22:30:16 +0530283 "RemoteRoleMapping/" + std::to_string(index));
284 return;
285 }
286 }
287 else if (thisJson.empty())
288 {
289 // Don't do anything for the empty objects,parse next json
290 // eg {"RemoteRoleMapping",[{}]}
291 }
292 else
293 {
294 // update/create the object
295 std::optional<std::string> remoteGroup;
296 std::optional<std::string> localRole;
297
Ed Tanousf23b7292020-10-15 09:41:17 -0700298 // This is a copy, but it's required in this case because of how
299 // readJson is structured
300 nlohmann::json thisJsonCopy = thisJson;
301 if (!json_util::readJson(thisJsonCopy, asyncResp->res,
302 "RemoteGroup", remoteGroup, "LocalRole",
303 localRole))
Ratan Gupta06785242019-07-26 22:30:16 +0530304 {
305 continue;
306 }
307
308 // Update existing RoleMapping Object
309 if (index < roleMapObjData.size())
310 {
311 BMCWEB_LOG_DEBUG << "Update Role Map Object";
312 // If "RemoteGroup" info is provided
313 if (remoteGroup)
314 {
315 crow::connections::systemBus->async_method_call(
316 [asyncResp, roleMapObjData, serverType, index,
317 remoteGroup](const boost::system::error_code ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700318 if (ec)
319 {
320 BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
321 messages::internalError(asyncResp->res);
322 return;
323 }
324 asyncResp->res
325 .jsonValue[serverType]["RemoteRoleMapping"][index]
326 ["RemoteGroup"] = *remoteGroup;
Ratan Gupta06785242019-07-26 22:30:16 +0530327 },
328 ldapDbusService, roleMapObjData[index].first,
329 propertyInterface, "Set",
330 "xyz.openbmc_project.User.PrivilegeMapperEntry",
331 "GroupName",
Ed Tanous168e20c2021-12-13 14:39:53 -0800332 dbus::utility::DbusVariantType(
333 std::move(*remoteGroup)));
Ratan Gupta06785242019-07-26 22:30:16 +0530334 }
335
336 // If "LocalRole" info is provided
337 if (localRole)
338 {
339 crow::connections::systemBus->async_method_call(
340 [asyncResp, roleMapObjData, serverType, index,
341 localRole](const boost::system::error_code ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700342 if (ec)
343 {
344 BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
345 messages::internalError(asyncResp->res);
346 return;
347 }
348 asyncResp->res
349 .jsonValue[serverType]["RemoteRoleMapping"][index]
350 ["LocalRole"] = *localRole;
Ratan Gupta06785242019-07-26 22:30:16 +0530351 },
352 ldapDbusService, roleMapObjData[index].first,
353 propertyInterface, "Set",
354 "xyz.openbmc_project.User.PrivilegeMapperEntry",
355 "Privilege",
Ed Tanous168e20c2021-12-13 14:39:53 -0800356 dbus::utility::DbusVariantType(
Ratan Gupta06785242019-07-26 22:30:16 +0530357 getPrivilegeFromRoleId(std::move(*localRole))));
358 }
359 }
360 // Create a new RoleMapping Object.
361 else
362 {
363 BMCWEB_LOG_DEBUG
364 << "setRoleMappingProperties: Creating new Object";
365 std::string pathString =
366 "RemoteRoleMapping/" + std::to_string(index);
367
368 if (!localRole)
369 {
370 messages::propertyMissing(asyncResp->res,
371 pathString + "/LocalRole");
372 continue;
373 }
374 if (!remoteGroup)
375 {
376 messages::propertyMissing(asyncResp->res,
377 pathString + "/RemoteGroup");
378 continue;
379 }
380
381 std::string dbusObjectPath;
382 if (serverType == "ActiveDirectory")
383 {
Ed Tanous2c70f802020-09-28 14:29:23 -0700384 dbusObjectPath = adConfigObject;
Ratan Gupta06785242019-07-26 22:30:16 +0530385 }
386 else if (serverType == "LDAP")
387 {
Ed Tanous23a21a12020-07-25 04:45:05 +0000388 dbusObjectPath = ldapConfigObjectName;
Ratan Gupta06785242019-07-26 22:30:16 +0530389 }
390
391 BMCWEB_LOG_DEBUG << "Remote Group=" << *remoteGroup
392 << ",LocalRole=" << *localRole;
393
394 crow::connections::systemBus->async_method_call(
Ed Tanous271584a2019-07-09 16:24:22 -0700395 [asyncResp, serverType, localRole,
Ratan Gupta06785242019-07-26 22:30:16 +0530396 remoteGroup](const boost::system::error_code ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700397 if (ec)
398 {
399 BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
400 messages::internalError(asyncResp->res);
401 return;
402 }
403 nlohmann::json& remoteRoleJson =
404 asyncResp->res
405 .jsonValue[serverType]["RemoteRoleMapping"];
406 nlohmann::json::object_t roleMapEntry;
407 roleMapEntry["LocalRole"] = *localRole;
408 roleMapEntry["RemoteGroup"] = *remoteGroup;
409 remoteRoleJson.push_back(std::move(roleMapEntry));
Ratan Gupta06785242019-07-26 22:30:16 +0530410 },
411 ldapDbusService, dbusObjectPath, ldapPrivMapperInterface,
Ed Tanous3174e4d2020-10-07 11:41:22 -0700412 "Create", *remoteGroup,
Ratan Gupta06785242019-07-26 22:30:16 +0530413 getPrivilegeFromRoleId(std::move(*localRole)));
414 }
415 }
416 }
417}
418
419/**
Ratan Gupta6973a582018-12-13 18:25:44 +0530420 * Function that retrieves all properties for LDAP config object
421 * into JSON
422 */
423template <typename CallbackFunc>
424inline void getLDAPConfigData(const std::string& ldapType,
425 CallbackFunc&& callback)
426{
Ratan Guptaab828d72019-04-22 14:18:33 +0530427
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600428 const std::array<const char*, 2> interfaces = {ldapEnableInterface,
Ratan Gupta6973a582018-12-13 18:25:44 +0530429 ldapConfigInterface};
430
431 crow::connections::systemBus->async_method_call(
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600432 [callback, ldapType](const boost::system::error_code ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800433 const dbus::utility::MapperGetObject& resp) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700434 if (ec || resp.empty())
435 {
436 BMCWEB_LOG_ERROR
437 << "DBUS response error during getting of service name: " << ec;
438 LDAPConfigData empty{};
439 callback(false, empty, ldapType);
440 return;
441 }
442 std::string service = resp.begin()->first;
443 crow::connections::systemBus->async_method_call(
444 [callback,
445 ldapType](const boost::system::error_code errorCode,
446 const dbus::utility::ManagedObjectType& ldapObjects) {
447 LDAPConfigData confData{};
448 if (errorCode)
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600449 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700450 callback(false, confData, ldapType);
451 BMCWEB_LOG_ERROR << "D-Bus responses error: " << errorCode;
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600452 return;
453 }
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600454
Ed Tanous002d39b2022-05-31 08:59:27 -0700455 std::string ldapDbusType;
456 std::string searchString;
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600457
Ed Tanous002d39b2022-05-31 08:59:27 -0700458 if (ldapType == "LDAP")
459 {
460 ldapDbusType =
461 "xyz.openbmc_project.User.Ldap.Config.Type.OpenLdap";
462 searchString = "openldap";
463 }
464 else if (ldapType == "ActiveDirectory")
465 {
466 ldapDbusType =
467 "xyz.openbmc_project.User.Ldap.Config.Type.ActiveDirectory";
468 searchString = "active_directory";
469 }
470 else
471 {
472 BMCWEB_LOG_ERROR << "Can't get the DbusType for the given type="
473 << ldapType;
474 callback(false, confData, ldapType);
475 return;
476 }
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600477
Ed Tanous002d39b2022-05-31 08:59:27 -0700478 std::string ldapEnableInterfaceStr = ldapEnableInterface;
479 std::string ldapConfigInterfaceStr = ldapConfigInterface;
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600480
Ed Tanous002d39b2022-05-31 08:59:27 -0700481 for (const auto& object : ldapObjects)
482 {
483 // let's find the object whose ldap type is equal to the
484 // given type
485 if (object.first.str.find(searchString) == std::string::npos)
486 {
487 continue;
488 }
489
490 for (const auto& interface : object.second)
491 {
492 if (interface.first == ldapEnableInterfaceStr)
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600493 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700494 // rest of the properties are string.
495 for (const auto& property : interface.second)
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600496 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700497 if (property.first == "Enabled")
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600498 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700499 const bool* value =
500 std::get_if<bool>(&property.second);
501 if (value == nullptr)
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600502 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700503 continue;
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600504 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700505 confData.serviceEnabled = *value;
506 break;
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600507 }
508 }
509 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700510 else if (interface.first == ldapConfigInterfaceStr)
511 {
512
513 for (const auto& property : interface.second)
514 {
515 const std::string* strValue =
516 std::get_if<std::string>(&property.second);
517 if (strValue == nullptr)
518 {
519 continue;
520 }
521 if (property.first == "LDAPServerURI")
522 {
523 confData.uri = *strValue;
524 }
525 else if (property.first == "LDAPBindDN")
526 {
527 confData.bindDN = *strValue;
528 }
529 else if (property.first == "LDAPBaseDN")
530 {
531 confData.baseDN = *strValue;
532 }
533 else if (property.first == "LDAPSearchScope")
534 {
535 confData.searchScope = *strValue;
536 }
537 else if (property.first == "GroupNameAttribute")
538 {
539 confData.groupAttribute = *strValue;
540 }
541 else if (property.first == "UserNameAttribute")
542 {
543 confData.userNameAttribute = *strValue;
544 }
545 else if (property.first == "LDAPType")
546 {
547 confData.serverType = *strValue;
548 }
549 }
550 }
551 else if (interface.first ==
552 "xyz.openbmc_project.User.PrivilegeMapperEntry")
553 {
554 LDAPRoleMapData roleMapData{};
555 for (const auto& property : interface.second)
556 {
557 const std::string* strValue =
558 std::get_if<std::string>(&property.second);
559
560 if (strValue == nullptr)
561 {
562 continue;
563 }
564
565 if (property.first == "GroupName")
566 {
567 roleMapData.groupName = *strValue;
568 }
569 else if (property.first == "Privilege")
570 {
571 roleMapData.privilege = *strValue;
572 }
573 }
574
575 confData.groupRoleList.emplace_back(object.first.str,
576 roleMapData);
577 }
578 }
579 }
580 callback(true, confData, ldapType);
581 },
582 service, ldapRootObject, dbusObjManagerIntf, "GetManagedObjects");
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600583 },
584 mapperBusName, mapperObjectPath, mapperIntf, "GetObject",
Ed Tanous23a21a12020-07-25 04:45:05 +0000585 ldapConfigObjectName, interfaces);
Ratan Gupta6973a582018-12-13 18:25:44 +0530586}
587
Ed Tanous6c51eab2021-06-03 12:30:29 -0700588/**
589 * @brief parses the authentication section under the LDAP
590 * @param input JSON data
591 * @param asyncResp pointer to the JSON response
592 * @param userName userName to be filled from the given JSON.
593 * @param password password to be filled from the given JSON.
594 */
Ed Tanous4f48d5f2021-06-21 08:27:45 -0700595inline void parseLDAPAuthenticationJson(
Ed Tanous6c51eab2021-06-03 12:30:29 -0700596 nlohmann::json input, const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
597 std::optional<std::string>& username, std::optional<std::string>& password)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700598{
Ed Tanous6c51eab2021-06-03 12:30:29 -0700599 std::optional<std::string> authType;
600
601 if (!json_util::readJson(input, asyncResp->res, "AuthenticationType",
602 authType, "Username", username, "Password",
603 password))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700604 {
Ed Tanous6c51eab2021-06-03 12:30:29 -0700605 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700606 }
Ed Tanous6c51eab2021-06-03 12:30:29 -0700607 if (!authType)
Ratan Gupta8a07d282019-03-16 08:33:47 +0530608 {
Ed Tanous6c51eab2021-06-03 12:30:29 -0700609 return;
Ratan Gupta8a07d282019-03-16 08:33:47 +0530610 }
Ed Tanous6c51eab2021-06-03 12:30:29 -0700611 if (*authType != "UsernameAndPassword")
Ratan Gupta8a07d282019-03-16 08:33:47 +0530612 {
Ed Tanous6c51eab2021-06-03 12:30:29 -0700613 messages::propertyValueNotInList(asyncResp->res, *authType,
614 "AuthenticationType");
615 return;
Ratan Gupta8a07d282019-03-16 08:33:47 +0530616 }
Ed Tanous6c51eab2021-06-03 12:30:29 -0700617}
618/**
619 * @brief parses the LDAPService section under the LDAP
620 * @param input JSON data
621 * @param asyncResp pointer to the JSON response
622 * @param baseDNList baseDN to be filled from the given JSON.
623 * @param userNameAttribute userName to be filled from the given JSON.
624 * @param groupaAttribute password to be filled from the given JSON.
625 */
Ratan Gupta8a07d282019-03-16 08:33:47 +0530626
Ed Tanous4f48d5f2021-06-21 08:27:45 -0700627inline void
628 parseLDAPServiceJson(nlohmann::json input,
629 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
630 std::optional<std::vector<std::string>>& baseDNList,
631 std::optional<std::string>& userNameAttribute,
632 std::optional<std::string>& groupsAttribute)
Ed Tanous6c51eab2021-06-03 12:30:29 -0700633{
634 std::optional<nlohmann::json> searchSettings;
635
636 if (!json_util::readJson(input, asyncResp->res, "SearchSettings",
637 searchSettings))
Ratan Gupta8a07d282019-03-16 08:33:47 +0530638 {
Ed Tanous6c51eab2021-06-03 12:30:29 -0700639 return;
Ratan Gupta8a07d282019-03-16 08:33:47 +0530640 }
Ed Tanous6c51eab2021-06-03 12:30:29 -0700641 if (!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 (!json_util::readJson(*searchSettings, asyncResp->res,
646 "BaseDistinguishedNames", baseDNList,
647 "UsernameAttribute", userNameAttribute,
648 "GroupsAttribute", groupsAttribute))
Ratan Gupta8a07d282019-03-16 08:33:47 +0530649 {
Ed Tanous6c51eab2021-06-03 12:30:29 -0700650 return;
Ratan Gupta8a07d282019-03-16 08:33:47 +0530651 }
Ed Tanous6c51eab2021-06-03 12:30:29 -0700652}
653/**
654 * @brief updates the LDAP server address and updates the
655 json response with the new value.
656 * @param serviceAddressList address to be updated.
657 * @param asyncResp pointer to the JSON response
658 * @param ldapServerElementName Type of LDAP
659 server(openLDAP/ActiveDirectory)
660 */
Ratan Gupta8a07d282019-03-16 08:33:47 +0530661
Ed Tanous4f48d5f2021-06-21 08:27:45 -0700662inline void handleServiceAddressPatch(
Ed Tanous6c51eab2021-06-03 12:30:29 -0700663 const std::vector<std::string>& serviceAddressList,
664 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
665 const std::string& ldapServerElementName,
666 const std::string& ldapConfigObject)
667{
668 crow::connections::systemBus->async_method_call(
669 [asyncResp, ldapServerElementName,
670 serviceAddressList](const boost::system::error_code ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700671 if (ec)
672 {
673 BMCWEB_LOG_DEBUG
674 << "Error Occurred in updating the service address";
675 messages::internalError(asyncResp->res);
676 return;
677 }
678 std::vector<std::string> modifiedserviceAddressList = {
679 serviceAddressList.front()};
680 asyncResp->res.jsonValue[ldapServerElementName]["ServiceAddresses"] =
681 modifiedserviceAddressList;
682 if ((serviceAddressList).size() > 1)
683 {
684 messages::propertyValueModified(asyncResp->res, "ServiceAddresses",
685 serviceAddressList.front());
686 }
687 BMCWEB_LOG_DEBUG << "Updated the service address";
Ed Tanous6c51eab2021-06-03 12:30:29 -0700688 },
689 ldapDbusService, ldapConfigObject, propertyInterface, "Set",
690 ldapConfigInterface, "LDAPServerURI",
Ed Tanous168e20c2021-12-13 14:39:53 -0800691 dbus::utility::DbusVariantType(serviceAddressList.front()));
Ed Tanous6c51eab2021-06-03 12:30:29 -0700692}
693/**
694 * @brief updates the LDAP Bind DN and updates the
695 json response with the new value.
696 * @param username name of the user which needs to be updated.
697 * @param asyncResp pointer to the JSON response
698 * @param ldapServerElementName Type of LDAP
699 server(openLDAP/ActiveDirectory)
700 */
Ratan Gupta8a07d282019-03-16 08:33:47 +0530701
Ed Tanous4f48d5f2021-06-21 08:27:45 -0700702inline void
703 handleUserNamePatch(const std::string& username,
704 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
705 const std::string& ldapServerElementName,
706 const std::string& ldapConfigObject)
Ed Tanous6c51eab2021-06-03 12:30:29 -0700707{
708 crow::connections::systemBus->async_method_call(
709 [asyncResp, username,
710 ldapServerElementName](const boost::system::error_code ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700711 if (ec)
712 {
713 BMCWEB_LOG_DEBUG << "Error occurred in updating the username";
714 messages::internalError(asyncResp->res);
715 return;
716 }
717 asyncResp->res
718 .jsonValue[ldapServerElementName]["Authentication"]["Username"] =
719 username;
720 BMCWEB_LOG_DEBUG << "Updated the username";
Ed Tanous6c51eab2021-06-03 12:30:29 -0700721 },
722 ldapDbusService, ldapConfigObject, propertyInterface, "Set",
Ed Tanous168e20c2021-12-13 14:39:53 -0800723 ldapConfigInterface, "LDAPBindDN",
724 dbus::utility::DbusVariantType(username));
Ed Tanous6c51eab2021-06-03 12:30:29 -0700725}
726
727/**
728 * @brief updates the LDAP password
729 * @param password : ldap password which needs to be updated.
730 * @param asyncResp pointer to the JSON response
731 * @param ldapServerElementName Type of LDAP
732 * server(openLDAP/ActiveDirectory)
733 */
734
Ed Tanous4f48d5f2021-06-21 08:27:45 -0700735inline void
736 handlePasswordPatch(const std::string& password,
737 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
738 const std::string& ldapServerElementName,
739 const std::string& ldapConfigObject)
Ed Tanous6c51eab2021-06-03 12:30:29 -0700740{
741 crow::connections::systemBus->async_method_call(
742 [asyncResp, password,
743 ldapServerElementName](const boost::system::error_code ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700744 if (ec)
745 {
746 BMCWEB_LOG_DEBUG << "Error occurred in updating the password";
747 messages::internalError(asyncResp->res);
748 return;
749 }
750 asyncResp->res
751 .jsonValue[ldapServerElementName]["Authentication"]["Password"] =
752 "";
753 BMCWEB_LOG_DEBUG << "Updated the password";
Ed Tanous6c51eab2021-06-03 12:30:29 -0700754 },
755 ldapDbusService, ldapConfigObject, propertyInterface, "Set",
756 ldapConfigInterface, "LDAPBindDNPassword",
Ed Tanous168e20c2021-12-13 14:39:53 -0800757 dbus::utility::DbusVariantType(password));
Ed Tanous6c51eab2021-06-03 12:30:29 -0700758}
759
760/**
761 * @brief updates the LDAP BaseDN and updates the
762 json response with the new value.
763 * @param baseDNList baseDN list which needs to be updated.
764 * @param asyncResp pointer to the JSON response
765 * @param ldapServerElementName Type of LDAP
766 server(openLDAP/ActiveDirectory)
767 */
768
Ed Tanous4f48d5f2021-06-21 08:27:45 -0700769inline void
770 handleBaseDNPatch(const std::vector<std::string>& baseDNList,
771 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
772 const std::string& ldapServerElementName,
773 const std::string& ldapConfigObject)
Ed Tanous6c51eab2021-06-03 12:30:29 -0700774{
775 crow::connections::systemBus->async_method_call(
776 [asyncResp, baseDNList,
777 ldapServerElementName](const boost::system::error_code ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700778 if (ec)
779 {
780 BMCWEB_LOG_DEBUG << "Error Occurred in Updating the base DN";
781 messages::internalError(asyncResp->res);
782 return;
783 }
784 auto& serverTypeJson = asyncResp->res.jsonValue[ldapServerElementName];
785 auto& searchSettingsJson =
786 serverTypeJson["LDAPService"]["SearchSettings"];
787 std::vector<std::string> modifiedBaseDNList = {baseDNList.front()};
788 searchSettingsJson["BaseDistinguishedNames"] = modifiedBaseDNList;
789 if (baseDNList.size() > 1)
790 {
791 messages::propertyValueModified(
792 asyncResp->res, "BaseDistinguishedNames", baseDNList.front());
793 }
794 BMCWEB_LOG_DEBUG << "Updated the base DN";
Ed Tanous6c51eab2021-06-03 12:30:29 -0700795 },
796 ldapDbusService, ldapConfigObject, propertyInterface, "Set",
797 ldapConfigInterface, "LDAPBaseDN",
Ed Tanous168e20c2021-12-13 14:39:53 -0800798 dbus::utility::DbusVariantType(baseDNList.front()));
Ed Tanous6c51eab2021-06-03 12:30:29 -0700799}
800/**
801 * @brief updates the LDAP user name attribute and updates the
802 json response with the new value.
803 * @param userNameAttribute attribute to be updated.
804 * @param asyncResp pointer to the JSON response
805 * @param ldapServerElementName Type of LDAP
806 server(openLDAP/ActiveDirectory)
807 */
808
Ed Tanous4f48d5f2021-06-21 08:27:45 -0700809inline void
810 handleUserNameAttrPatch(const std::string& userNameAttribute,
811 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
812 const std::string& ldapServerElementName,
813 const std::string& ldapConfigObject)
Ed Tanous6c51eab2021-06-03 12:30:29 -0700814{
815 crow::connections::systemBus->async_method_call(
816 [asyncResp, userNameAttribute,
817 ldapServerElementName](const boost::system::error_code ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700818 if (ec)
819 {
820 BMCWEB_LOG_DEBUG << "Error Occurred in Updating the "
821 "username attribute";
822 messages::internalError(asyncResp->res);
823 return;
824 }
825 auto& serverTypeJson = asyncResp->res.jsonValue[ldapServerElementName];
826 auto& searchSettingsJson =
827 serverTypeJson["LDAPService"]["SearchSettings"];
828 searchSettingsJson["UsernameAttribute"] = userNameAttribute;
829 BMCWEB_LOG_DEBUG << "Updated the user name attr.";
Ed Tanous6c51eab2021-06-03 12:30:29 -0700830 },
831 ldapDbusService, ldapConfigObject, propertyInterface, "Set",
832 ldapConfigInterface, "UserNameAttribute",
Ed Tanous168e20c2021-12-13 14:39:53 -0800833 dbus::utility::DbusVariantType(userNameAttribute));
Ed Tanous6c51eab2021-06-03 12:30:29 -0700834}
835/**
836 * @brief updates the LDAP group attribute and updates the
837 json response with the new value.
838 * @param groupsAttribute attribute to be updated.
839 * @param asyncResp pointer to the JSON response
840 * @param ldapServerElementName Type of LDAP
841 server(openLDAP/ActiveDirectory)
842 */
843
Ed Tanous4f48d5f2021-06-21 08:27:45 -0700844inline void handleGroupNameAttrPatch(
Ed Tanous6c51eab2021-06-03 12:30:29 -0700845 const std::string& groupsAttribute,
846 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
847 const std::string& ldapServerElementName,
848 const std::string& ldapConfigObject)
849{
850 crow::connections::systemBus->async_method_call(
851 [asyncResp, groupsAttribute,
852 ldapServerElementName](const boost::system::error_code ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700853 if (ec)
854 {
855 BMCWEB_LOG_DEBUG << "Error Occurred in Updating the "
856 "groupname attribute";
857 messages::internalError(asyncResp->res);
858 return;
859 }
860 auto& serverTypeJson = asyncResp->res.jsonValue[ldapServerElementName];
861 auto& searchSettingsJson =
862 serverTypeJson["LDAPService"]["SearchSettings"];
863 searchSettingsJson["GroupsAttribute"] = groupsAttribute;
864 BMCWEB_LOG_DEBUG << "Updated the groupname attr";
Ed Tanous6c51eab2021-06-03 12:30:29 -0700865 },
866 ldapDbusService, ldapConfigObject, propertyInterface, "Set",
867 ldapConfigInterface, "GroupNameAttribute",
Ed Tanous168e20c2021-12-13 14:39:53 -0800868 dbus::utility::DbusVariantType(groupsAttribute));
Ed Tanous6c51eab2021-06-03 12:30:29 -0700869}
870/**
871 * @brief updates the LDAP service enable and updates the
872 json response with the new value.
873 * @param input JSON data.
874 * @param asyncResp pointer to the JSON response
875 * @param ldapServerElementName Type of LDAP
876 server(openLDAP/ActiveDirectory)
877 */
878
Ed Tanous4f48d5f2021-06-21 08:27:45 -0700879inline void handleServiceEnablePatch(
Ed Tanous6c51eab2021-06-03 12:30:29 -0700880 bool serviceEnabled, const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
881 const std::string& ldapServerElementName,
882 const std::string& ldapConfigObject)
883{
884 crow::connections::systemBus->async_method_call(
885 [asyncResp, serviceEnabled,
886 ldapServerElementName](const boost::system::error_code ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700887 if (ec)
888 {
889 BMCWEB_LOG_DEBUG << "Error Occurred in Updating the service enable";
890 messages::internalError(asyncResp->res);
891 return;
892 }
893 asyncResp->res.jsonValue[ldapServerElementName]["ServiceEnabled"] =
894 serviceEnabled;
895 BMCWEB_LOG_DEBUG << "Updated Service enable = " << serviceEnabled;
Ed Tanous6c51eab2021-06-03 12:30:29 -0700896 },
897 ldapDbusService, ldapConfigObject, propertyInterface, "Set",
Ed Tanous168e20c2021-12-13 14:39:53 -0800898 ldapEnableInterface, "Enabled",
899 dbus::utility::DbusVariantType(serviceEnabled));
Ed Tanous6c51eab2021-06-03 12:30:29 -0700900}
901
Ed Tanous4f48d5f2021-06-21 08:27:45 -0700902inline void
903 handleAuthMethodsPatch(nlohmann::json& input,
904 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Ed Tanous6c51eab2021-06-03 12:30:29 -0700905{
906 std::optional<bool> basicAuth;
907 std::optional<bool> cookie;
908 std::optional<bool> sessionToken;
909 std::optional<bool> xToken;
910 std::optional<bool> tls;
911
912 if (!json_util::readJson(input, asyncResp->res, "BasicAuth", basicAuth,
913 "Cookie", cookie, "SessionToken", sessionToken,
914 "XToken", xToken, "TLS", tls))
Ratan Gupta8a07d282019-03-16 08:33:47 +0530915 {
Ed Tanous6c51eab2021-06-03 12:30:29 -0700916 BMCWEB_LOG_ERROR << "Cannot read values from AuthMethod tag";
917 return;
918 }
919
920 // Make a copy of methods configuration
921 persistent_data::AuthConfigMethods authMethodsConfig =
922 persistent_data::SessionStore::getInstance().getAuthMethodsConfig();
923
924 if (basicAuth)
925 {
926#ifndef BMCWEB_ENABLE_BASIC_AUTHENTICATION
927 messages::actionNotSupported(
George Liu0fda0f12021-11-16 10:06:17 +0800928 asyncResp->res,
929 "Setting BasicAuth when basic-auth feature is disabled");
Ed Tanous6c51eab2021-06-03 12:30:29 -0700930 return;
931#endif
932 authMethodsConfig.basic = *basicAuth;
933 }
934
935 if (cookie)
936 {
937#ifndef BMCWEB_ENABLE_COOKIE_AUTHENTICATION
George Liu0fda0f12021-11-16 10:06:17 +0800938 messages::actionNotSupported(
939 asyncResp->res,
940 "Setting Cookie when cookie-auth feature is disabled");
Ed Tanous6c51eab2021-06-03 12:30:29 -0700941 return;
942#endif
943 authMethodsConfig.cookie = *cookie;
944 }
945
946 if (sessionToken)
947 {
948#ifndef BMCWEB_ENABLE_SESSION_AUTHENTICATION
949 messages::actionNotSupported(
George Liu0fda0f12021-11-16 10:06:17 +0800950 asyncResp->res,
951 "Setting SessionToken when session-auth feature is disabled");
Ed Tanous6c51eab2021-06-03 12:30:29 -0700952 return;
953#endif
954 authMethodsConfig.sessionToken = *sessionToken;
955 }
956
957 if (xToken)
958 {
959#ifndef BMCWEB_ENABLE_XTOKEN_AUTHENTICATION
George Liu0fda0f12021-11-16 10:06:17 +0800960 messages::actionNotSupported(
961 asyncResp->res,
962 "Setting XToken when xtoken-auth feature is disabled");
Ed Tanous6c51eab2021-06-03 12:30:29 -0700963 return;
964#endif
965 authMethodsConfig.xtoken = *xToken;
966 }
967
968 if (tls)
969 {
970#ifndef BMCWEB_ENABLE_MUTUAL_TLS_AUTHENTICATION
George Liu0fda0f12021-11-16 10:06:17 +0800971 messages::actionNotSupported(
972 asyncResp->res,
973 "Setting TLS when mutual-tls-auth feature is disabled");
Ed Tanous6c51eab2021-06-03 12:30:29 -0700974 return;
975#endif
976 authMethodsConfig.tls = *tls;
977 }
978
979 if (!authMethodsConfig.basic && !authMethodsConfig.cookie &&
980 !authMethodsConfig.sessionToken && !authMethodsConfig.xtoken &&
981 !authMethodsConfig.tls)
982 {
983 // Do not allow user to disable everything
984 messages::actionNotSupported(asyncResp->res,
985 "of disabling all available methods");
986 return;
987 }
988
989 persistent_data::SessionStore::getInstance().updateAuthMethodsConfig(
990 authMethodsConfig);
991 // Save configuration immediately
992 persistent_data::getConfig().writeData();
993
994 messages::success(asyncResp->res);
995}
996
997/**
998 * @brief Get the required values from the given JSON, validates the
999 * value and create the LDAP config object.
1000 * @param input JSON data
1001 * @param asyncResp pointer to the JSON response
1002 * @param serverType Type of LDAP server(openLDAP/ActiveDirectory)
1003 */
1004
1005inline void handleLDAPPatch(nlohmann::json& input,
1006 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1007 const std::string& serverType)
1008{
1009 std::string dbusObjectPath;
1010 if (serverType == "ActiveDirectory")
1011 {
1012 dbusObjectPath = adConfigObject;
1013 }
1014 else if (serverType == "LDAP")
1015 {
1016 dbusObjectPath = ldapConfigObjectName;
1017 }
1018 else
1019 {
1020 return;
1021 }
1022
1023 std::optional<nlohmann::json> authentication;
1024 std::optional<nlohmann::json> ldapService;
1025 std::optional<std::vector<std::string>> serviceAddressList;
1026 std::optional<bool> serviceEnabled;
1027 std::optional<std::vector<std::string>> baseDNList;
1028 std::optional<std::string> userNameAttribute;
1029 std::optional<std::string> groupsAttribute;
1030 std::optional<std::string> userName;
1031 std::optional<std::string> password;
1032 std::optional<std::vector<nlohmann::json>> remoteRoleMapData;
1033
1034 if (!json_util::readJson(input, asyncResp->res, "Authentication",
1035 authentication, "LDAPService", ldapService,
1036 "ServiceAddresses", serviceAddressList,
1037 "ServiceEnabled", serviceEnabled,
1038 "RemoteRoleMapping", remoteRoleMapData))
1039 {
1040 return;
1041 }
1042
1043 if (authentication)
1044 {
1045 parseLDAPAuthenticationJson(*authentication, asyncResp, userName,
1046 password);
1047 }
1048 if (ldapService)
1049 {
1050 parseLDAPServiceJson(*ldapService, asyncResp, baseDNList,
1051 userNameAttribute, groupsAttribute);
1052 }
1053 if (serviceAddressList)
1054 {
Ed Tanous26f69762022-01-25 09:49:11 -08001055 if (serviceAddressList->empty())
Ratan Guptaeb2bbe52019-04-22 14:27:01 +05301056 {
Ed Tanous6c51eab2021-06-03 12:30:29 -07001057 messages::propertyValueNotInList(asyncResp->res, "[]",
1058 "ServiceAddress");
Ed Tanouscb13a392020-07-25 19:02:03 +00001059 return;
1060 }
Ed Tanous6c51eab2021-06-03 12:30:29 -07001061 }
1062 if (baseDNList)
1063 {
Ed Tanous26f69762022-01-25 09:49:11 -08001064 if (baseDNList->empty())
Ratan Gupta8a07d282019-03-16 08:33:47 +05301065 {
Ed Tanous6c51eab2021-06-03 12:30:29 -07001066 messages::propertyValueNotInList(asyncResp->res, "[]",
1067 "BaseDistinguishedNames");
Ratan Gupta8a07d282019-03-16 08:33:47 +05301068 return;
1069 }
Ed Tanous6c51eab2021-06-03 12:30:29 -07001070 }
Ratan Gupta8a07d282019-03-16 08:33:47 +05301071
Ed Tanous6c51eab2021-06-03 12:30:29 -07001072 // nothing to update, then return
1073 if (!userName && !password && !serviceAddressList && !baseDNList &&
1074 !userNameAttribute && !groupsAttribute && !serviceEnabled &&
1075 !remoteRoleMapData)
1076 {
1077 return;
1078 }
1079
1080 // Get the existing resource first then keep modifying
1081 // whenever any property gets updated.
Ed Tanous002d39b2022-05-31 08:59:27 -07001082 getLDAPConfigData(
1083 serverType,
1084 [asyncResp, userName, password, baseDNList, userNameAttribute,
1085 groupsAttribute, serviceAddressList, serviceEnabled, dbusObjectPath,
1086 remoteRoleMapData](bool success, const LDAPConfigData& confData,
1087 const std::string& serverT) {
Ed Tanous6c51eab2021-06-03 12:30:29 -07001088 if (!success)
Ratan Gupta8a07d282019-03-16 08:33:47 +05301089 {
Ed Tanous6c51eab2021-06-03 12:30:29 -07001090 messages::internalError(asyncResp->res);
1091 return;
Ratan Gupta8a07d282019-03-16 08:33:47 +05301092 }
Ed Tanous6c51eab2021-06-03 12:30:29 -07001093 parseLDAPConfigData(asyncResp->res.jsonValue, confData, serverT);
1094 if (confData.serviceEnabled)
Ratan Gupta8a07d282019-03-16 08:33:47 +05301095 {
Ed Tanous6c51eab2021-06-03 12:30:29 -07001096 // Disable the service first and update the rest of
1097 // the properties.
1098 handleServiceEnablePatch(false, asyncResp, serverT, dbusObjectPath);
Ratan Gupta8a07d282019-03-16 08:33:47 +05301099 }
Ed Tanous6c51eab2021-06-03 12:30:29 -07001100
Ratan Gupta8a07d282019-03-16 08:33:47 +05301101 if (serviceAddressList)
1102 {
Ed Tanous6c51eab2021-06-03 12:30:29 -07001103 handleServiceAddressPatch(*serviceAddressList, asyncResp, serverT,
1104 dbusObjectPath);
Ratan Gupta8a07d282019-03-16 08:33:47 +05301105 }
Ed Tanous6c51eab2021-06-03 12:30:29 -07001106 if (userName)
1107 {
1108 handleUserNamePatch(*userName, asyncResp, serverT, dbusObjectPath);
1109 }
1110 if (password)
1111 {
1112 handlePasswordPatch(*password, asyncResp, serverT, dbusObjectPath);
1113 }
1114
Ratan Gupta8a07d282019-03-16 08:33:47 +05301115 if (baseDNList)
1116 {
Ed Tanous6c51eab2021-06-03 12:30:29 -07001117 handleBaseDNPatch(*baseDNList, asyncResp, serverT, dbusObjectPath);
1118 }
1119 if (userNameAttribute)
1120 {
1121 handleUserNameAttrPatch(*userNameAttribute, asyncResp, serverT,
1122 dbusObjectPath);
1123 }
1124 if (groupsAttribute)
1125 {
1126 handleGroupNameAttrPatch(*groupsAttribute, asyncResp, serverT,
1127 dbusObjectPath);
1128 }
1129 if (serviceEnabled)
1130 {
1131 // if user has given the value as true then enable
1132 // the service. if user has given false then no-op
1133 // as service is already stopped.
1134 if (*serviceEnabled)
Ratan Gupta8a07d282019-03-16 08:33:47 +05301135 {
Ed Tanous6c51eab2021-06-03 12:30:29 -07001136 handleServiceEnablePatch(*serviceEnabled, asyncResp, serverT,
1137 dbusObjectPath);
Ratan Gupta8a07d282019-03-16 08:33:47 +05301138 }
1139 }
jayaprakash Mutyala96200602020-04-08 11:09:10 +00001140 else
1141 {
Ed Tanous6c51eab2021-06-03 12:30:29 -07001142 // if user has not given the service enabled value
1143 // then revert it to the same state as it was
1144 // before.
1145 handleServiceEnablePatch(confData.serviceEnabled, asyncResp,
1146 serverT, dbusObjectPath);
jayaprakash Mutyala96200602020-04-08 11:09:10 +00001147 }
Ed Tanous04ae99e2018-09-20 15:54:36 -07001148
Ed Tanous6c51eab2021-06-03 12:30:29 -07001149 if (remoteRoleMapData)
1150 {
1151 handleRoleMapPatch(asyncResp, confData.groupRoleList, serverT,
1152 *remoteRoleMapData);
1153 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001154 });
Ed Tanous6c51eab2021-06-03 12:30:29 -07001155}
1156
1157inline void updateUserProperties(std::shared_ptr<bmcweb::AsyncResp> asyncResp,
1158 const std::string& username,
Ed Tanous618c14b2022-06-30 17:44:25 -07001159 const std::optional<std::string>& password,
1160 const std::optional<bool>& enabled,
1161 const std::optional<std::string>& roleId,
1162 const std::optional<bool>& locked)
Ed Tanous6c51eab2021-06-03 12:30:29 -07001163{
P Dheeraj Srujan Kumarb477fd42021-12-16 07:17:51 +05301164 sdbusplus::message::object_path tempObjPath(rootUserDbusPath);
1165 tempObjPath /= username;
1166 std::string dbusObjectPath(tempObjPath);
Ed Tanous6c51eab2021-06-03 12:30:29 -07001167
1168 dbus::utility::checkDbusPathExists(
Ed Tanous618c14b2022-06-30 17:44:25 -07001169 dbusObjectPath, [dbusObjectPath, username, password, roleId, enabled,
1170 locked, asyncResp{std::move(asyncResp)}](int rc) {
1171 if (rc <= 0)
Ed Tanous6c51eab2021-06-03 12:30:29 -07001172 {
Jiaqing Zhaod8a5d5d2022-08-05 16:21:51 +08001173 messages::resourceNotFound(asyncResp->res, "ManagerAccount",
1174 username);
Ed Tanous6c51eab2021-06-03 12:30:29 -07001175 return;
1176 }
Ed Tanous6c51eab2021-06-03 12:30:29 -07001177
Ed Tanous618c14b2022-06-30 17:44:25 -07001178 if (password)
1179 {
1180 int retval = pamUpdatePassword(username, *password);
1181
1182 if (retval == PAM_USER_UNKNOWN)
1183 {
1184 messages::resourceNotFound(asyncResp->res, "ManagerAccount",
1185 username);
1186 }
1187 else if (retval == PAM_AUTHTOK_ERR)
1188 {
1189 // If password is invalid
1190 messages::propertyValueFormatError(asyncResp->res,
1191 *password, "Password");
1192 BMCWEB_LOG_ERROR << "pamUpdatePassword Failed";
1193 }
1194 else if (retval != PAM_SUCCESS)
1195 {
1196 messages::internalError(asyncResp->res);
1197 return;
1198 }
1199 else
1200 {
1201 messages::success(asyncResp->res);
1202 }
1203 }
1204
1205 if (enabled)
1206 {
1207 crow::connections::systemBus->async_method_call(
1208 [asyncResp](const boost::system::error_code ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001209 if (ec)
Ed Tanous04ae99e2018-09-20 15:54:36 -07001210 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001211 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
Ayushi Smriti599c71d2019-08-23 17:43:18 +00001212 messages::internalError(asyncResp->res);
Ed Tanous04ae99e2018-09-20 15:54:36 -07001213 return;
1214 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001215 messages::success(asyncResp->res);
1216 return;
Ed Tanous618c14b2022-06-30 17:44:25 -07001217 },
1218 "xyz.openbmc_project.User.Manager", dbusObjectPath,
1219 "org.freedesktop.DBus.Properties", "Set",
1220 "xyz.openbmc_project.User.Attributes", "UserEnabled",
1221 dbus::utility::DbusVariantType{*enabled});
Ed Tanous002d39b2022-05-31 08:59:27 -07001222 }
Ed Tanous04ae99e2018-09-20 15:54:36 -07001223
Ed Tanous618c14b2022-06-30 17:44:25 -07001224 if (roleId)
1225 {
1226 std::string priv = getPrivilegeFromRoleId(*roleId);
1227 if (priv.empty())
1228 {
1229 messages::propertyValueNotInList(asyncResp->res, *roleId,
1230 "RoleId");
1231 return;
1232 }
1233
1234 crow::connections::systemBus->async_method_call(
1235 [asyncResp](const boost::system::error_code ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001236 if (ec)
Ed Tanous04ae99e2018-09-20 15:54:36 -07001237 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001238 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
1239 messages::internalError(asyncResp->res);
Ed Tanous6c51eab2021-06-03 12:30:29 -07001240 return;
1241 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001242 messages::success(asyncResp->res);
Ed Tanous618c14b2022-06-30 17:44:25 -07001243 },
1244 "xyz.openbmc_project.User.Manager", dbusObjectPath,
1245 "org.freedesktop.DBus.Properties", "Set",
1246 "xyz.openbmc_project.User.Attributes", "UserPrivilege",
1247 dbus::utility::DbusVariantType{priv});
Ed Tanous6c51eab2021-06-03 12:30:29 -07001248 }
1249
Ed Tanous618c14b2022-06-30 17:44:25 -07001250 if (locked)
1251 {
1252 // admin can unlock the account which is locked by
1253 // successive authentication failures but admin should
1254 // not be allowed to lock an account.
1255 if (*locked)
1256 {
1257 messages::propertyValueNotInList(asyncResp->res, "true",
1258 "Locked");
1259 return;
1260 }
1261
1262 crow::connections::systemBus->async_method_call(
1263 [asyncResp](const boost::system::error_code ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001264 if (ec)
Ed Tanous6c51eab2021-06-03 12:30:29 -07001265 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001266 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
1267 messages::internalError(asyncResp->res);
Ed Tanous04ae99e2018-09-20 15:54:36 -07001268 return;
1269 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001270 messages::success(asyncResp->res);
1271 return;
Ed Tanous618c14b2022-06-30 17:44:25 -07001272 },
1273 "xyz.openbmc_project.User.Manager", dbusObjectPath,
1274 "org.freedesktop.DBus.Properties", "Set",
1275 "xyz.openbmc_project.User.Attributes",
1276 "UserLockedForFailedAttempt",
1277 dbus::utility::DbusVariantType{*locked});
1278 }
Ed Tanous6c51eab2021-06-03 12:30:29 -07001279 });
1280}
Ed Tanousb9b2e0b2018-09-13 13:47:50 -07001281
Ed Tanous4c7d4d32022-07-07 15:29:35 -07001282inline void handleAccountServiceHead(
1283 App& app, const crow::Request& req,
1284 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Ed Tanous1ef4c342022-05-12 16:12:36 -07001285{
Ed Tanous4c7d4d32022-07-07 15:29:35 -07001286
Ed Tanous1ef4c342022-05-12 16:12:36 -07001287 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1288 {
1289 return;
1290 }
Ed Tanous4c7d4d32022-07-07 15:29:35 -07001291 asyncResp->res.addHeader(
1292 boost::beast::http::field::link,
1293 "</redfish/v1/JsonSchemas/AccountService/AccountService.json>; rel=describedby");
1294}
1295
1296inline void
1297 handleAccountServiceGet(App& app, const crow::Request& req,
1298 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1299{
1300 handleAccountServiceHead(app, req, asyncResp);
Ed Tanous1ef4c342022-05-12 16:12:36 -07001301 const persistent_data::AuthConfigMethods& authMethodsConfig =
1302 persistent_data::SessionStore::getInstance().getAuthMethodsConfig();
1303
1304 nlohmann::json& json = asyncResp->res.jsonValue;
1305 json["@odata.id"] = "/redfish/v1/AccountService";
1306 json["@odata.type"] = "#AccountService."
1307 "v1_10_0.AccountService";
1308 json["Id"] = "AccountService";
1309 json["Name"] = "Account Service";
1310 json["Description"] = "Account Service";
1311 json["ServiceEnabled"] = true;
1312 json["MaxPasswordLength"] = 20;
1313 json["Accounts"]["@odata.id"] = "/redfish/v1/AccountService/Accounts";
1314 json["Roles"]["@odata.id"] = "/redfish/v1/AccountService/Roles";
1315 json["Oem"]["OpenBMC"]["@odata.type"] =
1316 "#OemAccountService.v1_0_0.AccountService";
1317 json["Oem"]["OpenBMC"]["@odata.id"] =
1318 "/redfish/v1/AccountService#/Oem/OpenBMC";
1319 json["Oem"]["OpenBMC"]["AuthMethods"]["BasicAuth"] =
1320 authMethodsConfig.basic;
1321 json["Oem"]["OpenBMC"]["AuthMethods"]["SessionToken"] =
1322 authMethodsConfig.sessionToken;
1323 json["Oem"]["OpenBMC"]["AuthMethods"]["XToken"] = authMethodsConfig.xtoken;
1324 json["Oem"]["OpenBMC"]["AuthMethods"]["Cookie"] = authMethodsConfig.cookie;
1325 json["Oem"]["OpenBMC"]["AuthMethods"]["TLS"] = authMethodsConfig.tls;
1326
1327 // /redfish/v1/AccountService/LDAP/Certificates is something only
1328 // ConfigureManager can access then only display when the user has
1329 // permissions ConfigureManager
1330 Privileges effectiveUserPrivileges =
1331 redfish::getUserPrivileges(req.userRole);
1332
1333 if (isOperationAllowedWithPrivileges({{"ConfigureManager"}},
1334 effectiveUserPrivileges))
1335 {
1336 asyncResp->res.jsonValue["LDAP"]["Certificates"]["@odata.id"] =
1337 "/redfish/v1/AccountService/LDAP/Certificates";
1338 }
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001339 sdbusplus::asio::getAllProperties(
1340 *crow::connections::systemBus, "xyz.openbmc_project.User.Manager",
1341 "/xyz/openbmc_project/user", "xyz.openbmc_project.User.AccountPolicy",
Ed Tanous1ef4c342022-05-12 16:12:36 -07001342 [asyncResp](const boost::system::error_code ec,
1343 const dbus::utility::DBusPropertiesMap& propertiesList) {
1344 if (ec)
1345 {
1346 messages::internalError(asyncResp->res);
1347 return;
1348 }
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001349
Ed Tanous1ef4c342022-05-12 16:12:36 -07001350 BMCWEB_LOG_DEBUG << "Got " << propertiesList.size()
1351 << "properties for AccountService";
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001352
1353 const uint8_t* minPasswordLength = nullptr;
1354 const uint32_t* accountUnlockTimeout = nullptr;
1355 const uint16_t* maxLoginAttemptBeforeLockout = nullptr;
1356
1357 const bool success = sdbusplus::unpackPropertiesNoThrow(
1358 dbus_utils::UnpackErrorPrinter(), propertiesList,
1359 "MinPasswordLength", minPasswordLength, "AccountUnlockTimeout",
1360 accountUnlockTimeout, "MaxLoginAttemptBeforeLockout",
1361 maxLoginAttemptBeforeLockout);
1362
1363 if (!success)
Ed Tanous1ef4c342022-05-12 16:12:36 -07001364 {
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001365 messages::internalError(asyncResp->res);
1366 return;
Ed Tanous1ef4c342022-05-12 16:12:36 -07001367 }
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001368
1369 if (minPasswordLength != nullptr)
1370 {
1371 asyncResp->res.jsonValue["MinPasswordLength"] = *minPasswordLength;
1372 }
1373
1374 if (accountUnlockTimeout != nullptr)
1375 {
1376 asyncResp->res.jsonValue["AccountLockoutDuration"] =
1377 *accountUnlockTimeout;
1378 }
1379
1380 if (maxLoginAttemptBeforeLockout != nullptr)
1381 {
1382 asyncResp->res.jsonValue["AccountLockoutThreshold"] =
1383 *maxLoginAttemptBeforeLockout;
1384 }
1385 });
Ed Tanous1ef4c342022-05-12 16:12:36 -07001386
Ed Tanous02cad962022-06-30 16:50:15 -07001387 auto callback = [asyncResp](bool success, const LDAPConfigData& confData,
Ed Tanous1ef4c342022-05-12 16:12:36 -07001388 const std::string& ldapType) {
1389 if (!success)
1390 {
1391 return;
1392 }
1393 parseLDAPConfigData(asyncResp->res.jsonValue, confData, ldapType);
1394 };
1395
1396 getLDAPConfigData("LDAP", callback);
1397 getLDAPConfigData("ActiveDirectory", callback);
1398}
1399
1400inline void handleAccountServicePatch(
1401 App& app, const crow::Request& req,
1402 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1403{
1404 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1405 {
1406 return;
1407 }
1408 std::optional<uint32_t> unlockTimeout;
1409 std::optional<uint16_t> lockoutThreshold;
1410 std::optional<uint8_t> minPasswordLength;
1411 std::optional<uint16_t> maxPasswordLength;
1412 std::optional<nlohmann::json> ldapObject;
1413 std::optional<nlohmann::json> activeDirectoryObject;
1414 std::optional<nlohmann::json> oemObject;
1415
1416 if (!json_util::readJsonPatch(
1417 req, asyncResp->res, "AccountLockoutDuration", unlockTimeout,
1418 "AccountLockoutThreshold", lockoutThreshold, "MaxPasswordLength",
1419 maxPasswordLength, "MinPasswordLength", minPasswordLength, "LDAP",
1420 ldapObject, "ActiveDirectory", activeDirectoryObject, "Oem",
1421 oemObject))
1422 {
1423 return;
1424 }
1425
1426 if (minPasswordLength)
1427 {
1428 crow::connections::systemBus->async_method_call(
1429 [asyncResp](const boost::system::error_code ec) {
1430 if (ec)
1431 {
1432 messages::internalError(asyncResp->res);
1433 return;
1434 }
1435 messages::success(asyncResp->res);
1436 },
1437 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
1438 "org.freedesktop.DBus.Properties", "Set",
1439 "xyz.openbmc_project.User.AccountPolicy", "MinPasswordLength",
1440 dbus::utility::DbusVariantType(*minPasswordLength));
1441 }
1442
1443 if (maxPasswordLength)
1444 {
1445 messages::propertyNotWritable(asyncResp->res, "MaxPasswordLength");
1446 }
1447
1448 if (ldapObject)
1449 {
1450 handleLDAPPatch(*ldapObject, asyncResp, "LDAP");
1451 }
1452
1453 if (std::optional<nlohmann::json> oemOpenBMCObject;
1454 oemObject && json_util::readJson(*oemObject, asyncResp->res, "OpenBMC",
1455 oemOpenBMCObject))
1456 {
1457 if (std::optional<nlohmann::json> authMethodsObject;
1458 oemOpenBMCObject &&
1459 json_util::readJson(*oemOpenBMCObject, asyncResp->res,
1460 "AuthMethods", authMethodsObject))
1461 {
1462 if (authMethodsObject)
1463 {
1464 handleAuthMethodsPatch(*authMethodsObject, asyncResp);
1465 }
1466 }
1467 }
1468
1469 if (activeDirectoryObject)
1470 {
1471 handleLDAPPatch(*activeDirectoryObject, asyncResp, "ActiveDirectory");
1472 }
1473
1474 if (unlockTimeout)
1475 {
1476 crow::connections::systemBus->async_method_call(
1477 [asyncResp](const boost::system::error_code ec) {
1478 if (ec)
1479 {
1480 messages::internalError(asyncResp->res);
1481 return;
1482 }
1483 messages::success(asyncResp->res);
1484 },
1485 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
1486 "org.freedesktop.DBus.Properties", "Set",
1487 "xyz.openbmc_project.User.AccountPolicy", "AccountUnlockTimeout",
1488 dbus::utility::DbusVariantType(*unlockTimeout));
1489 }
1490 if (lockoutThreshold)
1491 {
1492 crow::connections::systemBus->async_method_call(
1493 [asyncResp](const boost::system::error_code ec) {
1494 if (ec)
1495 {
1496 messages::internalError(asyncResp->res);
1497 return;
1498 }
1499 messages::success(asyncResp->res);
1500 },
1501 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
1502 "org.freedesktop.DBus.Properties", "Set",
1503 "xyz.openbmc_project.User.AccountPolicy",
1504 "MaxLoginAttemptBeforeLockout",
1505 dbus::utility::DbusVariantType(*lockoutThreshold));
1506 }
1507}
1508
Ed Tanous4c7d4d32022-07-07 15:29:35 -07001509inline void handleAccountCollectionHead(
Ed Tanous1ef4c342022-05-12 16:12:36 -07001510 App& app, const crow::Request& req,
1511 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1512{
Ed Tanous4c7d4d32022-07-07 15:29:35 -07001513
Ed Tanous1ef4c342022-05-12 16:12:36 -07001514 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1515 {
1516 return;
1517 }
Ed Tanous4c7d4d32022-07-07 15:29:35 -07001518 asyncResp->res.addHeader(
1519 boost::beast::http::field::link,
1520 "</redfish/v1/JsonSchemas/ManagerAccountCollection.json>; rel=describedby");
1521}
1522
1523inline void handleAccountCollectionGet(
1524 App& app, const crow::Request& req,
1525 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1526{
1527 handleAccountCollectionHead(app, req, asyncResp);
Ed Tanous1ef4c342022-05-12 16:12:36 -07001528
1529 asyncResp->res.jsonValue["@odata.id"] =
1530 "/redfish/v1/AccountService/Accounts";
1531 asyncResp->res.jsonValue["@odata.type"] = "#ManagerAccountCollection."
1532 "ManagerAccountCollection";
1533 asyncResp->res.jsonValue["Name"] = "Accounts Collection";
1534 asyncResp->res.jsonValue["Description"] = "BMC User Accounts";
1535
1536 Privileges effectiveUserPrivileges =
1537 redfish::getUserPrivileges(req.userRole);
1538
1539 std::string thisUser;
1540 if (req.session)
1541 {
1542 thisUser = req.session->username;
1543 }
1544 crow::connections::systemBus->async_method_call(
1545 [asyncResp, thisUser, effectiveUserPrivileges](
1546 const boost::system::error_code ec,
1547 const dbus::utility::ManagedObjectType& users) {
1548 if (ec)
1549 {
1550 messages::internalError(asyncResp->res);
1551 return;
1552 }
1553
1554 bool userCanSeeAllAccounts =
1555 effectiveUserPrivileges.isSupersetOf({"ConfigureUsers"});
1556
1557 bool userCanSeeSelf =
1558 effectiveUserPrivileges.isSupersetOf({"ConfigureSelf"});
1559
1560 nlohmann::json& memberArray = asyncResp->res.jsonValue["Members"];
1561 memberArray = nlohmann::json::array();
1562
1563 for (const auto& userpath : users)
1564 {
1565 std::string user = userpath.first.filename();
1566 if (user.empty())
1567 {
1568 messages::internalError(asyncResp->res);
1569 BMCWEB_LOG_ERROR << "Invalid firmware ID";
1570
1571 return;
1572 }
1573
1574 // As clarified by Redfish here:
1575 // https://redfishforum.com/thread/281/manageraccountcollection-change-allows-account-enumeration
1576 // Users without ConfigureUsers, only see their own
1577 // account. Users with ConfigureUsers, see all
1578 // accounts.
1579 if (userCanSeeAllAccounts || (thisUser == user && userCanSeeSelf))
1580 {
1581 nlohmann::json::object_t member;
1582 member["@odata.id"] =
1583 "/redfish/v1/AccountService/Accounts/" + user;
1584 memberArray.push_back(std::move(member));
1585 }
1586 }
1587 asyncResp->res.jsonValue["Members@odata.count"] = memberArray.size();
1588 },
1589 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
1590 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
1591}
1592
1593inline void handleAccountCollectionPost(
1594 App& app, const crow::Request& req,
1595 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1596{
1597 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1598 {
1599 return;
1600 }
1601 std::string username;
1602 std::string password;
1603 std::optional<std::string> roleId("User");
1604 std::optional<bool> enabled = true;
1605 if (!json_util::readJsonPatch(req, asyncResp->res, "UserName", username,
1606 "Password", password, "RoleId", roleId,
1607 "Enabled", enabled))
1608 {
1609 return;
1610 }
1611
1612 std::string priv = getPrivilegeFromRoleId(*roleId);
1613 if (priv.empty())
1614 {
1615 messages::propertyValueNotInList(asyncResp->res, *roleId, "RoleId");
1616 return;
1617 }
Asmitha Karunanithi239adf82022-03-25 02:59:03 -05001618 roleId = priv;
Ed Tanous1ef4c342022-05-12 16:12:36 -07001619
1620 // Reading AllGroups property
1621 sdbusplus::asio::getProperty<std::vector<std::string>>(
1622 *crow::connections::systemBus, "xyz.openbmc_project.User.Manager",
1623 "/xyz/openbmc_project/user", "xyz.openbmc_project.User.Manager",
1624 "AllGroups",
1625 [asyncResp, username, password{std::move(password)}, roleId,
1626 enabled](const boost::system::error_code ec,
1627 const std::vector<std::string>& allGroupsList) {
1628 if (ec)
1629 {
1630 BMCWEB_LOG_DEBUG << "ERROR with async_method_call";
1631 messages::internalError(asyncResp->res);
1632 return;
1633 }
1634
1635 if (allGroupsList.empty())
1636 {
1637 messages::internalError(asyncResp->res);
1638 return;
1639 }
1640
1641 crow::connections::systemBus->async_method_call(
1642 [asyncResp, username, password](const boost::system::error_code ec2,
Patrick Williams59d494e2022-07-22 19:26:55 -05001643 sdbusplus::message_t& m) {
Ed Tanous1ef4c342022-05-12 16:12:36 -07001644 if (ec2)
1645 {
1646 userErrorMessageHandler(m.get_error(), asyncResp, username, "");
1647 return;
1648 }
1649
1650 if (pamUpdatePassword(username, password) != PAM_SUCCESS)
1651 {
1652 // At this point we have a user that's been
1653 // created, but the password set
1654 // failed.Something is wrong, so delete the user
1655 // that we've already created
1656 sdbusplus::message::object_path tempObjPath(rootUserDbusPath);
1657 tempObjPath /= username;
1658 const std::string userPath(tempObjPath);
1659
1660 crow::connections::systemBus->async_method_call(
1661 [asyncResp, password](const boost::system::error_code ec3) {
1662 if (ec3)
1663 {
1664 messages::internalError(asyncResp->res);
1665 return;
1666 }
1667
1668 // If password is invalid
1669 messages::propertyValueFormatError(asyncResp->res, password,
1670 "Password");
1671 },
1672 "xyz.openbmc_project.User.Manager", userPath,
1673 "xyz.openbmc_project.Object.Delete", "Delete");
1674
1675 BMCWEB_LOG_ERROR << "pamUpdatePassword Failed";
1676 return;
1677 }
1678
1679 messages::created(asyncResp->res);
1680 asyncResp->res.addHeader(
1681 "Location", "/redfish/v1/AccountService/Accounts/" + username);
1682 },
1683 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
1684 "xyz.openbmc_project.User.Manager", "CreateUser", username,
1685 allGroupsList, *roleId, *enabled);
1686 });
1687}
1688
1689inline void
Ed Tanous4c7d4d32022-07-07 15:29:35 -07001690 handleAccountHead(App& app, const crow::Request& req,
1691 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1692 const std::string& /*accountName*/)
Ed Tanous1ef4c342022-05-12 16:12:36 -07001693{
Ed Tanous4c7d4d32022-07-07 15:29:35 -07001694
Ed Tanous1ef4c342022-05-12 16:12:36 -07001695 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1696 {
1697 return;
1698 }
Ed Tanous4c7d4d32022-07-07 15:29:35 -07001699 asyncResp->res.addHeader(
1700 boost::beast::http::field::link,
1701 "</redfish/v1/JsonSchemas/ManagerAccount/ManagerAccount.json>; rel=describedby");
1702}
1703inline void
1704 handleAccountGet(App& app, const crow::Request& req,
1705 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1706 const std::string& accountName)
1707{
1708 handleAccountHead(app, req, asyncResp, accountName);
Ed Tanous1ef4c342022-05-12 16:12:36 -07001709#ifdef BMCWEB_INSECURE_DISABLE_AUTHENTICATION
1710 // If authentication is disabled, there are no user accounts
Jiaqing Zhaod8a5d5d2022-08-05 16:21:51 +08001711 messages::resourceNotFound(asyncResp->res, "ManagerAccount", accountName);
Ed Tanous1ef4c342022-05-12 16:12:36 -07001712 return;
1713
1714#endif // BMCWEB_INSECURE_DISABLE_AUTHENTICATION
1715 if (req.session == nullptr)
1716 {
1717 messages::internalError(asyncResp->res);
1718 return;
1719 }
1720 if (req.session->username != accountName)
1721 {
1722 // At this point we've determined that the user is trying to
1723 // modify a user that isn't them. We need to verify that they
1724 // have permissions to modify other users, so re-run the auth
1725 // check with the same permissions, minus ConfigureSelf.
1726 Privileges effectiveUserPrivileges =
1727 redfish::getUserPrivileges(req.userRole);
1728 Privileges requiredPermissionsToChangeNonSelf = {"ConfigureUsers",
1729 "ConfigureManager"};
1730 if (!effectiveUserPrivileges.isSupersetOf(
1731 requiredPermissionsToChangeNonSelf))
1732 {
1733 BMCWEB_LOG_DEBUG << "GET Account denied access";
1734 messages::insufficientPrivilege(asyncResp->res);
1735 return;
1736 }
1737 }
1738
1739 crow::connections::systemBus->async_method_call(
1740 [asyncResp,
1741 accountName](const boost::system::error_code ec,
1742 const dbus::utility::ManagedObjectType& users) {
1743 if (ec)
1744 {
1745 messages::internalError(asyncResp->res);
1746 return;
1747 }
1748 const auto userIt = std::find_if(
1749 users.begin(), users.end(),
1750 [accountName](
1751 const std::pair<sdbusplus::message::object_path,
1752 dbus::utility::DBusInteracesMap>& user) {
1753 return accountName == user.first.filename();
1754 });
1755
1756 if (userIt == users.end())
1757 {
1758 messages::resourceNotFound(asyncResp->res, "ManagerAccount",
1759 accountName);
1760 return;
1761 }
1762
1763 asyncResp->res.jsonValue["@odata.type"] =
1764 "#ManagerAccount.v1_4_0.ManagerAccount";
1765 asyncResp->res.jsonValue["Name"] = "User Account";
1766 asyncResp->res.jsonValue["Description"] = "User Account";
1767 asyncResp->res.jsonValue["Password"] = nullptr;
Ed Tanous1ef4c342022-05-12 16:12:36 -07001768
1769 for (const auto& interface : userIt->second)
1770 {
1771 if (interface.first == "xyz.openbmc_project.User.Attributes")
1772 {
1773 for (const auto& property : interface.second)
1774 {
1775 if (property.first == "UserEnabled")
1776 {
1777 const bool* userEnabled =
1778 std::get_if<bool>(&property.second);
1779 if (userEnabled == nullptr)
1780 {
1781 BMCWEB_LOG_ERROR << "UserEnabled wasn't a bool";
1782 messages::internalError(asyncResp->res);
1783 return;
1784 }
1785 asyncResp->res.jsonValue["Enabled"] = *userEnabled;
1786 }
1787 else if (property.first == "UserLockedForFailedAttempt")
1788 {
1789 const bool* userLocked =
1790 std::get_if<bool>(&property.second);
1791 if (userLocked == nullptr)
1792 {
1793 BMCWEB_LOG_ERROR << "UserLockedForF"
1794 "ailedAttempt "
1795 "wasn't a bool";
1796 messages::internalError(asyncResp->res);
1797 return;
1798 }
1799 asyncResp->res.jsonValue["Locked"] = *userLocked;
1800 asyncResp->res
1801 .jsonValue["Locked@Redfish.AllowableValues"] = {
1802 "false"}; // can only unlock accounts
1803 }
1804 else if (property.first == "UserPrivilege")
1805 {
1806 const std::string* userPrivPtr =
1807 std::get_if<std::string>(&property.second);
1808 if (userPrivPtr == nullptr)
1809 {
1810 BMCWEB_LOG_ERROR << "UserPrivilege wasn't a "
1811 "string";
1812 messages::internalError(asyncResp->res);
1813 return;
1814 }
1815 std::string role = getRoleIdFromPrivilege(*userPrivPtr);
1816 if (role.empty())
1817 {
1818 BMCWEB_LOG_ERROR << "Invalid user role";
1819 messages::internalError(asyncResp->res);
1820 return;
1821 }
1822 asyncResp->res.jsonValue["RoleId"] = role;
1823
1824 nlohmann::json& roleEntry =
1825 asyncResp->res.jsonValue["Links"]["Role"];
1826 roleEntry["@odata.id"] =
1827 "/redfish/v1/AccountService/Roles/" + role;
1828 }
1829 else if (property.first == "UserPasswordExpired")
1830 {
1831 const bool* userPasswordExpired =
1832 std::get_if<bool>(&property.second);
1833 if (userPasswordExpired == nullptr)
1834 {
1835 BMCWEB_LOG_ERROR
1836 << "UserPasswordExpired wasn't a bool";
1837 messages::internalError(asyncResp->res);
1838 return;
1839 }
1840 asyncResp->res.jsonValue["PasswordChangeRequired"] =
1841 *userPasswordExpired;
1842 }
Abhishek Patelc7229812022-02-01 10:07:15 -06001843 else if (property.first == "UserGroups")
1844 {
1845 const std::vector<std::string>* userGroups =
1846 std::get_if<std::vector<std::string>>(
1847 &property.second);
1848 if (userGroups == nullptr)
1849 {
1850 BMCWEB_LOG_ERROR
1851 << "userGroups wasn't a string vector";
1852 messages::internalError(asyncResp->res);
1853 return;
1854 }
1855 if (!translateUserGroup(*userGroups, asyncResp->res))
1856 {
1857 BMCWEB_LOG_ERROR << "userGroups mapping failed";
1858 messages::internalError(asyncResp->res);
1859 return;
1860 }
1861 }
Ed Tanous1ef4c342022-05-12 16:12:36 -07001862 }
1863 }
1864 }
1865
1866 asyncResp->res.jsonValue["@odata.id"] =
1867 "/redfish/v1/AccountService/Accounts/" + accountName;
1868 asyncResp->res.jsonValue["Id"] = accountName;
1869 asyncResp->res.jsonValue["UserName"] = accountName;
1870 },
1871 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
1872 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
1873}
1874
1875inline void
1876 handleAccounttDelete(App& app, const crow::Request& req,
1877 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1878 const std::string& username)
1879{
1880 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1881 {
1882 return;
1883 }
1884
1885#ifdef BMCWEB_INSECURE_DISABLE_AUTHENTICATION
1886 // If authentication is disabled, there are no user accounts
Jiaqing Zhaod8a5d5d2022-08-05 16:21:51 +08001887 messages::resourceNotFound(asyncResp->res, "ManagerAccount", username);
Ed Tanous1ef4c342022-05-12 16:12:36 -07001888 return;
1889
1890#endif // BMCWEB_INSECURE_DISABLE_AUTHENTICATION
1891 sdbusplus::message::object_path tempObjPath(rootUserDbusPath);
1892 tempObjPath /= username;
1893 const std::string userPath(tempObjPath);
1894
1895 crow::connections::systemBus->async_method_call(
1896 [asyncResp, username](const boost::system::error_code ec) {
1897 if (ec)
1898 {
Jiaqing Zhaod8a5d5d2022-08-05 16:21:51 +08001899 messages::resourceNotFound(asyncResp->res, "ManagerAccount",
Ed Tanous1ef4c342022-05-12 16:12:36 -07001900 username);
1901 return;
1902 }
1903
1904 messages::accountRemoved(asyncResp->res);
1905 },
1906 "xyz.openbmc_project.User.Manager", userPath,
1907 "xyz.openbmc_project.Object.Delete", "Delete");
1908}
1909
1910inline void
1911 handleAccountPatch(App& app, const crow::Request& req,
1912 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1913 const std::string& username)
1914{
1915 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1916 {
1917 return;
1918 }
1919#ifdef BMCWEB_INSECURE_DISABLE_AUTHENTICATION
1920 // If authentication is disabled, there are no user accounts
Jiaqing Zhaod8a5d5d2022-08-05 16:21:51 +08001921 messages::resourceNotFound(asyncResp->res, "ManagerAccount", username);
Ed Tanous1ef4c342022-05-12 16:12:36 -07001922 return;
1923
1924#endif // BMCWEB_INSECURE_DISABLE_AUTHENTICATION
1925 std::optional<std::string> newUserName;
1926 std::optional<std::string> password;
1927 std::optional<bool> enabled;
1928 std::optional<std::string> roleId;
1929 std::optional<bool> locked;
1930
1931 if (req.session == nullptr)
1932 {
1933 messages::internalError(asyncResp->res);
1934 return;
1935 }
1936
1937 Privileges effectiveUserPrivileges =
1938 redfish::getUserPrivileges(req.userRole);
1939 Privileges configureUsers = {"ConfigureUsers"};
1940 bool userHasConfigureUsers =
1941 effectiveUserPrivileges.isSupersetOf(configureUsers);
1942 if (userHasConfigureUsers)
1943 {
1944 // Users with ConfigureUsers can modify for all users
1945 if (!json_util::readJsonPatch(req, asyncResp->res, "UserName",
1946 newUserName, "Password", password,
1947 "RoleId", roleId, "Enabled", enabled,
1948 "Locked", locked))
1949 {
1950 return;
1951 }
1952 }
1953 else
1954 {
1955 // ConfigureSelf accounts can only modify their own account
1956 if (username != req.session->username)
1957 {
1958 messages::insufficientPrivilege(asyncResp->res);
1959 return;
1960 }
1961
1962 // ConfigureSelf accounts can only modify their password
1963 if (!json_util::readJsonPatch(req, asyncResp->res, "Password",
1964 password))
1965 {
1966 return;
1967 }
1968 }
1969
1970 // if user name is not provided in the patch method or if it
1971 // matches the user name in the URI, then we are treating it as
1972 // updating user properties other then username. If username
1973 // provided doesn't match the URI, then we are treating this as
1974 // user rename request.
1975 if (!newUserName || (newUserName.value() == username))
1976 {
1977 updateUserProperties(asyncResp, username, password, enabled, roleId,
1978 locked);
1979 return;
1980 }
1981 crow::connections::systemBus->async_method_call(
1982 [asyncResp, username, password(std::move(password)),
1983 roleId(std::move(roleId)), enabled, newUser{std::string(*newUserName)},
Patrick Williams59d494e2022-07-22 19:26:55 -05001984 locked](const boost::system::error_code ec, sdbusplus::message_t& m) {
Ed Tanous1ef4c342022-05-12 16:12:36 -07001985 if (ec)
1986 {
1987 userErrorMessageHandler(m.get_error(), asyncResp, newUser,
1988 username);
1989 return;
1990 }
1991
1992 updateUserProperties(asyncResp, newUser, password, enabled, roleId,
1993 locked);
1994 },
1995 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
1996 "xyz.openbmc_project.User.Manager", "RenameUser", username,
1997 *newUserName);
1998}
1999
Ed Tanous6c51eab2021-06-03 12:30:29 -07002000inline void requestAccountServiceRoutes(App& app)
Ed Tanousb9b2e0b2018-09-13 13:47:50 -07002001{
Ed Tanousb9b2e0b2018-09-13 13:47:50 -07002002
Ed Tanous6c51eab2021-06-03 12:30:29 -07002003 BMCWEB_ROUTE(app, "/redfish/v1/AccountService/")
Ed Tanous4c7d4d32022-07-07 15:29:35 -07002004 .privileges(redfish::privileges::headAccountService)
2005 .methods(boost::beast::http::verb::head)(
2006 std::bind_front(handleAccountServiceHead, std::ref(app)));
2007
2008 BMCWEB_ROUTE(app, "/redfish/v1/AccountService/")
Ed Tanoused398212021-06-09 17:05:54 -07002009 .privileges(redfish::privileges::getAccountService)
Ed Tanous002d39b2022-05-31 08:59:27 -07002010 .methods(boost::beast::http::verb::get)(
Ed Tanous1ef4c342022-05-12 16:12:36 -07002011 std::bind_front(handleAccountServiceGet, std::ref(app)));
Ed Tanous6c51eab2021-06-03 12:30:29 -07002012
Ed Tanousf5ffd802021-07-19 10:55:33 -07002013 BMCWEB_ROUTE(app, "/redfish/v1/AccountService/")
Gunnar Mills1ec43ee2022-01-04 15:39:52 -06002014 .privileges(redfish::privileges::patchAccountService)
Ed Tanousf5ffd802021-07-19 10:55:33 -07002015 .methods(boost::beast::http::verb::patch)(
Ed Tanous1ef4c342022-05-12 16:12:36 -07002016 std::bind_front(handleAccountServicePatch, std::ref(app)));
Ed Tanousf5ffd802021-07-19 10:55:33 -07002017
Ed Tanous6c51eab2021-06-03 12:30:29 -07002018 BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/")
Ed Tanous4c7d4d32022-07-07 15:29:35 -07002019 .privileges(redfish::privileges::headManagerAccountCollection)
2020 .methods(boost::beast::http::verb::head)(
2021 std::bind_front(handleAccountCollectionHead, std::ref(app)));
2022
2023 BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/")
Ed Tanoused398212021-06-09 17:05:54 -07002024 .privileges(redfish::privileges::getManagerAccountCollection)
Ed Tanous6c51eab2021-06-03 12:30:29 -07002025 .methods(boost::beast::http::verb::get)(
Ed Tanous1ef4c342022-05-12 16:12:36 -07002026 std::bind_front(handleAccountCollectionGet, std::ref(app)));
Ed Tanous06e086d2018-09-19 17:19:52 -07002027
Ed Tanous6c51eab2021-06-03 12:30:29 -07002028 BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/")
Ed Tanoused398212021-06-09 17:05:54 -07002029 .privileges(redfish::privileges::postManagerAccountCollection)
Ed Tanous002d39b2022-05-31 08:59:27 -07002030 .methods(boost::beast::http::verb::post)(
Ed Tanous1ef4c342022-05-12 16:12:36 -07002031 std::bind_front(handleAccountCollectionPost, std::ref(app)));
Ed Tanous002d39b2022-05-31 08:59:27 -07002032
2033 BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/<str>/")
Ed Tanous4c7d4d32022-07-07 15:29:35 -07002034 .privileges(redfish::privileges::headManagerAccount)
2035 .methods(boost::beast::http::verb::head)(
2036 std::bind_front(handleAccountHead, std::ref(app)));
2037
2038 BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/<str>/")
Ed Tanous002d39b2022-05-31 08:59:27 -07002039 .privileges(redfish::privileges::getManagerAccount)
2040 .methods(boost::beast::http::verb::get)(
Ed Tanous1ef4c342022-05-12 16:12:36 -07002041 std::bind_front(handleAccountGet, std::ref(app)));
Ed Tanous6c51eab2021-06-03 12:30:29 -07002042
2043 BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002044 // TODO this privilege should be using the generated endpoints, but
2045 // because of the special handling of ConfigureSelf, it's not able to
2046 // yet
Ed Tanous6c51eab2021-06-03 12:30:29 -07002047 .privileges({{"ConfigureUsers"}, {"ConfigureSelf"}})
2048 .methods(boost::beast::http::verb::patch)(
Ed Tanous1ef4c342022-05-12 16:12:36 -07002049 std::bind_front(handleAccountPatch, std::ref(app)));
Ed Tanous6c51eab2021-06-03 12:30:29 -07002050
2051 BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002052 .privileges(redfish::privileges::deleteManagerAccount)
Ed Tanous6c51eab2021-06-03 12:30:29 -07002053 .methods(boost::beast::http::verb::delete_)(
Ed Tanous1ef4c342022-05-12 16:12:36 -07002054 std::bind_front(handleAccounttDelete, std::ref(app)));
Ed Tanous6c51eab2021-06-03 12:30:29 -07002055}
Lewanczyk, Dawid88d16c92018-02-02 14:51:09 +01002056
Ed Tanous1abe55e2018-09-05 08:30:59 -07002057} // namespace redfish