blob: 3a8ffbc9a48e70dfb60727037c8a2db56b9a46c2 [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 Tanous0ec8b832022-03-14 14:56:47 -070018#include "generated/enums/account_service.hpp"
19#include "registries/privilege_registry.hpp"
20
John Edward Broadbent7e860f12021-04-08 15:57:16 -070021#include <app.hpp>
Ratan Gupta24c85422019-01-30 19:41:24 +053022#include <dbus_utility.hpp>
Ed Tanous65b0dc32018-09-19 16:04:03 -070023#include <error_messages.hpp>
Ed Tanousb9b2e0b2018-09-13 13:47:50 -070024#include <openbmc_dbus_rest.hpp>
Ed Tanous52cc1122020-07-18 13:51:21 -070025#include <persistent_data.hpp>
Ed Tanous45ca1b82022-03-25 13:07:27 -070026#include <query.hpp>
Jonathan Doman1e1e5982021-06-11 09:36:17 -070027#include <sdbusplus/asio/property.hpp>
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +020028#include <sdbusplus/unpack_properties.hpp>
29#include <utils/dbus_utils.hpp>
Ed Tanousa8408792018-09-05 16:08:38 -070030#include <utils/json_utils.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
234 nlohmann::json::array_t remoteGroupArray;
235 nlohmann::json::object_t remoteGroup;
236 remoteGroup["RemoteGroup"] = obj.second.groupName;
237 remoteGroupArray.emplace_back(std::move(remoteGroup));
238 roleMapArray.emplace_back(std::move(remoteGroupArray));
239
240 nlohmann::json::array_t localRoleArray;
241 nlohmann::json::object_t localRole;
242 localRole["LocalRole"] = getRoleIdFromPrivilege(obj.second.privilege);
243 localRoleArray.emplace_back(std::move(localRole));
244 roleMapArray.emplace_back(std::move(localRoleArray));
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600245 }
Ratan Gupta6973a582018-12-13 18:25:44 +0530246}
247
248/**
Ratan Gupta06785242019-07-26 22:30:16 +0530249 * @brief validates given JSON input and then calls appropriate method to
250 * create, to delete or to set Rolemapping object based on the given input.
251 *
252 */
Ed Tanous23a21a12020-07-25 04:45:05 +0000253inline void handleRoleMapPatch(
zhanghch058d1b46d2021-04-01 11:18:24 +0800254 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ratan Gupta06785242019-07-26 22:30:16 +0530255 const std::vector<std::pair<std::string, LDAPRoleMapData>>& roleMapObjData,
Ed Tanousf23b7292020-10-15 09:41:17 -0700256 const std::string& serverType, const std::vector<nlohmann::json>& input)
Ratan Gupta06785242019-07-26 22:30:16 +0530257{
258 for (size_t index = 0; index < input.size(); index++)
259 {
Ed Tanousf23b7292020-10-15 09:41:17 -0700260 const nlohmann::json& thisJson = input[index];
Ratan Gupta06785242019-07-26 22:30:16 +0530261
262 if (thisJson.is_null())
263 {
264 // delete the existing object
265 if (index < roleMapObjData.size())
266 {
267 crow::connections::systemBus->async_method_call(
268 [asyncResp, roleMapObjData, serverType,
269 index](const boost::system::error_code ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700270 if (ec)
271 {
272 BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
273 messages::internalError(asyncResp->res);
274 return;
275 }
276 asyncResp->res
277 .jsonValue[serverType]["RemoteRoleMapping"][index] =
278 nullptr;
Ratan Gupta06785242019-07-26 22:30:16 +0530279 },
280 ldapDbusService, roleMapObjData[index].first,
281 "xyz.openbmc_project.Object.Delete", "Delete");
282 }
283 else
284 {
285 BMCWEB_LOG_ERROR << "Can't delete the object";
286 messages::propertyValueTypeError(
Ed Tanous71f52d92021-02-19 08:51:17 -0800287 asyncResp->res,
288 thisJson.dump(2, ' ', true,
289 nlohmann::json::error_handler_t::replace),
Ratan Gupta06785242019-07-26 22:30:16 +0530290 "RemoteRoleMapping/" + std::to_string(index));
291 return;
292 }
293 }
294 else if (thisJson.empty())
295 {
296 // Don't do anything for the empty objects,parse next json
297 // eg {"RemoteRoleMapping",[{}]}
298 }
299 else
300 {
301 // update/create the object
302 std::optional<std::string> remoteGroup;
303 std::optional<std::string> localRole;
304
Ed Tanousf23b7292020-10-15 09:41:17 -0700305 // This is a copy, but it's required in this case because of how
306 // readJson is structured
307 nlohmann::json thisJsonCopy = thisJson;
308 if (!json_util::readJson(thisJsonCopy, asyncResp->res,
309 "RemoteGroup", remoteGroup, "LocalRole",
310 localRole))
Ratan Gupta06785242019-07-26 22:30:16 +0530311 {
312 continue;
313 }
314
315 // Update existing RoleMapping Object
316 if (index < roleMapObjData.size())
317 {
318 BMCWEB_LOG_DEBUG << "Update Role Map Object";
319 // If "RemoteGroup" info is provided
320 if (remoteGroup)
321 {
322 crow::connections::systemBus->async_method_call(
323 [asyncResp, roleMapObjData, serverType, index,
324 remoteGroup](const boost::system::error_code ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700325 if (ec)
326 {
327 BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
328 messages::internalError(asyncResp->res);
329 return;
330 }
331 asyncResp->res
332 .jsonValue[serverType]["RemoteRoleMapping"][index]
333 ["RemoteGroup"] = *remoteGroup;
Ratan Gupta06785242019-07-26 22:30:16 +0530334 },
335 ldapDbusService, roleMapObjData[index].first,
336 propertyInterface, "Set",
337 "xyz.openbmc_project.User.PrivilegeMapperEntry",
338 "GroupName",
Ed Tanous168e20c2021-12-13 14:39:53 -0800339 dbus::utility::DbusVariantType(
340 std::move(*remoteGroup)));
Ratan Gupta06785242019-07-26 22:30:16 +0530341 }
342
343 // If "LocalRole" info is provided
344 if (localRole)
345 {
346 crow::connections::systemBus->async_method_call(
347 [asyncResp, roleMapObjData, serverType, index,
348 localRole](const boost::system::error_code ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700349 if (ec)
350 {
351 BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
352 messages::internalError(asyncResp->res);
353 return;
354 }
355 asyncResp->res
356 .jsonValue[serverType]["RemoteRoleMapping"][index]
357 ["LocalRole"] = *localRole;
Ratan Gupta06785242019-07-26 22:30:16 +0530358 },
359 ldapDbusService, roleMapObjData[index].first,
360 propertyInterface, "Set",
361 "xyz.openbmc_project.User.PrivilegeMapperEntry",
362 "Privilege",
Ed Tanous168e20c2021-12-13 14:39:53 -0800363 dbus::utility::DbusVariantType(
Ratan Gupta06785242019-07-26 22:30:16 +0530364 getPrivilegeFromRoleId(std::move(*localRole))));
365 }
366 }
367 // Create a new RoleMapping Object.
368 else
369 {
370 BMCWEB_LOG_DEBUG
371 << "setRoleMappingProperties: Creating new Object";
372 std::string pathString =
373 "RemoteRoleMapping/" + std::to_string(index);
374
375 if (!localRole)
376 {
377 messages::propertyMissing(asyncResp->res,
378 pathString + "/LocalRole");
379 continue;
380 }
381 if (!remoteGroup)
382 {
383 messages::propertyMissing(asyncResp->res,
384 pathString + "/RemoteGroup");
385 continue;
386 }
387
388 std::string dbusObjectPath;
389 if (serverType == "ActiveDirectory")
390 {
Ed Tanous2c70f802020-09-28 14:29:23 -0700391 dbusObjectPath = adConfigObject;
Ratan Gupta06785242019-07-26 22:30:16 +0530392 }
393 else if (serverType == "LDAP")
394 {
Ed Tanous23a21a12020-07-25 04:45:05 +0000395 dbusObjectPath = ldapConfigObjectName;
Ratan Gupta06785242019-07-26 22:30:16 +0530396 }
397
398 BMCWEB_LOG_DEBUG << "Remote Group=" << *remoteGroup
399 << ",LocalRole=" << *localRole;
400
401 crow::connections::systemBus->async_method_call(
Ed Tanous271584a2019-07-09 16:24:22 -0700402 [asyncResp, serverType, localRole,
Ratan Gupta06785242019-07-26 22:30:16 +0530403 remoteGroup](const boost::system::error_code ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700404 if (ec)
405 {
406 BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
407 messages::internalError(asyncResp->res);
408 return;
409 }
410 nlohmann::json& remoteRoleJson =
411 asyncResp->res
412 .jsonValue[serverType]["RemoteRoleMapping"];
413 nlohmann::json::object_t roleMapEntry;
414 roleMapEntry["LocalRole"] = *localRole;
415 roleMapEntry["RemoteGroup"] = *remoteGroup;
416 remoteRoleJson.push_back(std::move(roleMapEntry));
Ratan Gupta06785242019-07-26 22:30:16 +0530417 },
418 ldapDbusService, dbusObjectPath, ldapPrivMapperInterface,
Ed Tanous3174e4d2020-10-07 11:41:22 -0700419 "Create", *remoteGroup,
Ratan Gupta06785242019-07-26 22:30:16 +0530420 getPrivilegeFromRoleId(std::move(*localRole)));
421 }
422 }
423 }
424}
425
426/**
Ratan Gupta6973a582018-12-13 18:25:44 +0530427 * Function that retrieves all properties for LDAP config object
428 * into JSON
429 */
430template <typename CallbackFunc>
431inline void getLDAPConfigData(const std::string& ldapType,
432 CallbackFunc&& callback)
433{
Ratan Guptaab828d72019-04-22 14:18:33 +0530434
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600435 const std::array<const char*, 2> interfaces = {ldapEnableInterface,
Ratan Gupta6973a582018-12-13 18:25:44 +0530436 ldapConfigInterface};
437
438 crow::connections::systemBus->async_method_call(
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600439 [callback, ldapType](const boost::system::error_code ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800440 const dbus::utility::MapperGetObject& resp) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700441 if (ec || resp.empty())
442 {
443 BMCWEB_LOG_ERROR
444 << "DBUS response error during getting of service name: " << ec;
445 LDAPConfigData empty{};
446 callback(false, empty, ldapType);
447 return;
448 }
449 std::string service = resp.begin()->first;
450 crow::connections::systemBus->async_method_call(
451 [callback,
452 ldapType](const boost::system::error_code errorCode,
453 const dbus::utility::ManagedObjectType& ldapObjects) {
454 LDAPConfigData confData{};
455 if (errorCode)
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600456 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700457 callback(false, confData, ldapType);
458 BMCWEB_LOG_ERROR << "D-Bus responses error: " << errorCode;
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600459 return;
460 }
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600461
Ed Tanous002d39b2022-05-31 08:59:27 -0700462 std::string ldapDbusType;
463 std::string searchString;
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600464
Ed Tanous002d39b2022-05-31 08:59:27 -0700465 if (ldapType == "LDAP")
466 {
467 ldapDbusType =
468 "xyz.openbmc_project.User.Ldap.Config.Type.OpenLdap";
469 searchString = "openldap";
470 }
471 else if (ldapType == "ActiveDirectory")
472 {
473 ldapDbusType =
474 "xyz.openbmc_project.User.Ldap.Config.Type.ActiveDirectory";
475 searchString = "active_directory";
476 }
477 else
478 {
479 BMCWEB_LOG_ERROR << "Can't get the DbusType for the given type="
480 << ldapType;
481 callback(false, confData, ldapType);
482 return;
483 }
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600484
Ed Tanous002d39b2022-05-31 08:59:27 -0700485 std::string ldapEnableInterfaceStr = ldapEnableInterface;
486 std::string ldapConfigInterfaceStr = ldapConfigInterface;
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600487
Ed Tanous002d39b2022-05-31 08:59:27 -0700488 for (const auto& object : ldapObjects)
489 {
490 // let's find the object whose ldap type is equal to the
491 // given type
492 if (object.first.str.find(searchString) == std::string::npos)
493 {
494 continue;
495 }
496
497 for (const auto& interface : object.second)
498 {
499 if (interface.first == ldapEnableInterfaceStr)
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600500 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700501 // rest of the properties are string.
502 for (const auto& property : interface.second)
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600503 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700504 if (property.first == "Enabled")
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600505 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700506 const bool* value =
507 std::get_if<bool>(&property.second);
508 if (value == nullptr)
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600509 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700510 continue;
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600511 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700512 confData.serviceEnabled = *value;
513 break;
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600514 }
515 }
516 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700517 else if (interface.first == ldapConfigInterfaceStr)
518 {
519
520 for (const auto& property : interface.second)
521 {
522 const std::string* strValue =
523 std::get_if<std::string>(&property.second);
524 if (strValue == nullptr)
525 {
526 continue;
527 }
528 if (property.first == "LDAPServerURI")
529 {
530 confData.uri = *strValue;
531 }
532 else if (property.first == "LDAPBindDN")
533 {
534 confData.bindDN = *strValue;
535 }
536 else if (property.first == "LDAPBaseDN")
537 {
538 confData.baseDN = *strValue;
539 }
540 else if (property.first == "LDAPSearchScope")
541 {
542 confData.searchScope = *strValue;
543 }
544 else if (property.first == "GroupNameAttribute")
545 {
546 confData.groupAttribute = *strValue;
547 }
548 else if (property.first == "UserNameAttribute")
549 {
550 confData.userNameAttribute = *strValue;
551 }
552 else if (property.first == "LDAPType")
553 {
554 confData.serverType = *strValue;
555 }
556 }
557 }
558 else if (interface.first ==
559 "xyz.openbmc_project.User.PrivilegeMapperEntry")
560 {
561 LDAPRoleMapData roleMapData{};
562 for (const auto& property : interface.second)
563 {
564 const std::string* strValue =
565 std::get_if<std::string>(&property.second);
566
567 if (strValue == nullptr)
568 {
569 continue;
570 }
571
572 if (property.first == "GroupName")
573 {
574 roleMapData.groupName = *strValue;
575 }
576 else if (property.first == "Privilege")
577 {
578 roleMapData.privilege = *strValue;
579 }
580 }
581
582 confData.groupRoleList.emplace_back(object.first.str,
583 roleMapData);
584 }
585 }
586 }
587 callback(true, confData, ldapType);
588 },
589 service, ldapRootObject, dbusObjManagerIntf, "GetManagedObjects");
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600590 },
591 mapperBusName, mapperObjectPath, mapperIntf, "GetObject",
Ed Tanous23a21a12020-07-25 04:45:05 +0000592 ldapConfigObjectName, interfaces);
Ratan Gupta6973a582018-12-13 18:25:44 +0530593}
594
Ed Tanous6c51eab2021-06-03 12:30:29 -0700595/**
596 * @brief parses the authentication section under the LDAP
597 * @param input JSON data
598 * @param asyncResp pointer to the JSON response
599 * @param userName userName to be filled from the given JSON.
600 * @param password password to be filled from the given JSON.
601 */
Ed Tanous4f48d5f2021-06-21 08:27:45 -0700602inline void parseLDAPAuthenticationJson(
Ed Tanous6c51eab2021-06-03 12:30:29 -0700603 nlohmann::json input, const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
604 std::optional<std::string>& username, std::optional<std::string>& password)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700605{
Ed Tanous6c51eab2021-06-03 12:30:29 -0700606 std::optional<std::string> authType;
607
608 if (!json_util::readJson(input, asyncResp->res, "AuthenticationType",
609 authType, "Username", username, "Password",
610 password))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700611 {
Ed Tanous6c51eab2021-06-03 12:30:29 -0700612 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700613 }
Ed Tanous6c51eab2021-06-03 12:30:29 -0700614 if (!authType)
Ratan Gupta8a07d282019-03-16 08:33:47 +0530615 {
Ed Tanous6c51eab2021-06-03 12:30:29 -0700616 return;
Ratan Gupta8a07d282019-03-16 08:33:47 +0530617 }
Ed Tanous6c51eab2021-06-03 12:30:29 -0700618 if (*authType != "UsernameAndPassword")
Ratan Gupta8a07d282019-03-16 08:33:47 +0530619 {
Ed Tanous6c51eab2021-06-03 12:30:29 -0700620 messages::propertyValueNotInList(asyncResp->res, *authType,
621 "AuthenticationType");
622 return;
Ratan Gupta8a07d282019-03-16 08:33:47 +0530623 }
Ed Tanous6c51eab2021-06-03 12:30:29 -0700624}
625/**
626 * @brief parses the LDAPService section under the LDAP
627 * @param input JSON data
628 * @param asyncResp pointer to the JSON response
629 * @param baseDNList baseDN to be filled from the given JSON.
630 * @param userNameAttribute userName to be filled from the given JSON.
631 * @param groupaAttribute password to be filled from the given JSON.
632 */
Ratan Gupta8a07d282019-03-16 08:33:47 +0530633
Ed Tanous4f48d5f2021-06-21 08:27:45 -0700634inline void
635 parseLDAPServiceJson(nlohmann::json input,
636 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
637 std::optional<std::vector<std::string>>& baseDNList,
638 std::optional<std::string>& userNameAttribute,
639 std::optional<std::string>& groupsAttribute)
Ed Tanous6c51eab2021-06-03 12:30:29 -0700640{
641 std::optional<nlohmann::json> searchSettings;
642
643 if (!json_util::readJson(input, asyncResp->res, "SearchSettings",
644 searchSettings))
Ratan Gupta8a07d282019-03-16 08:33:47 +0530645 {
Ed Tanous6c51eab2021-06-03 12:30:29 -0700646 return;
Ratan Gupta8a07d282019-03-16 08:33:47 +0530647 }
Ed Tanous6c51eab2021-06-03 12:30:29 -0700648 if (!searchSettings)
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 if (!json_util::readJson(*searchSettings, asyncResp->res,
653 "BaseDistinguishedNames", baseDNList,
654 "UsernameAttribute", userNameAttribute,
655 "GroupsAttribute", groupsAttribute))
Ratan Gupta8a07d282019-03-16 08:33:47 +0530656 {
Ed Tanous6c51eab2021-06-03 12:30:29 -0700657 return;
Ratan Gupta8a07d282019-03-16 08:33:47 +0530658 }
Ed Tanous6c51eab2021-06-03 12:30:29 -0700659}
660/**
661 * @brief updates the LDAP server address and updates the
662 json response with the new value.
663 * @param serviceAddressList address to be updated.
664 * @param asyncResp pointer to the JSON response
665 * @param ldapServerElementName Type of LDAP
666 server(openLDAP/ActiveDirectory)
667 */
Ratan Gupta8a07d282019-03-16 08:33:47 +0530668
Ed Tanous4f48d5f2021-06-21 08:27:45 -0700669inline void handleServiceAddressPatch(
Ed Tanous6c51eab2021-06-03 12:30:29 -0700670 const std::vector<std::string>& serviceAddressList,
671 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
672 const std::string& ldapServerElementName,
673 const std::string& ldapConfigObject)
674{
675 crow::connections::systemBus->async_method_call(
676 [asyncResp, ldapServerElementName,
677 serviceAddressList](const boost::system::error_code ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700678 if (ec)
679 {
680 BMCWEB_LOG_DEBUG
681 << "Error Occurred in updating the service address";
682 messages::internalError(asyncResp->res);
683 return;
684 }
685 std::vector<std::string> modifiedserviceAddressList = {
686 serviceAddressList.front()};
687 asyncResp->res.jsonValue[ldapServerElementName]["ServiceAddresses"] =
688 modifiedserviceAddressList;
689 if ((serviceAddressList).size() > 1)
690 {
691 messages::propertyValueModified(asyncResp->res, "ServiceAddresses",
692 serviceAddressList.front());
693 }
694 BMCWEB_LOG_DEBUG << "Updated the service address";
Ed Tanous6c51eab2021-06-03 12:30:29 -0700695 },
696 ldapDbusService, ldapConfigObject, propertyInterface, "Set",
697 ldapConfigInterface, "LDAPServerURI",
Ed Tanous168e20c2021-12-13 14:39:53 -0800698 dbus::utility::DbusVariantType(serviceAddressList.front()));
Ed Tanous6c51eab2021-06-03 12:30:29 -0700699}
700/**
701 * @brief updates the LDAP Bind DN and updates the
702 json response with the new value.
703 * @param username name of the user which needs to be updated.
704 * @param asyncResp pointer to the JSON response
705 * @param ldapServerElementName Type of LDAP
706 server(openLDAP/ActiveDirectory)
707 */
Ratan Gupta8a07d282019-03-16 08:33:47 +0530708
Ed Tanous4f48d5f2021-06-21 08:27:45 -0700709inline void
710 handleUserNamePatch(const std::string& username,
711 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
712 const std::string& ldapServerElementName,
713 const std::string& ldapConfigObject)
Ed Tanous6c51eab2021-06-03 12:30:29 -0700714{
715 crow::connections::systemBus->async_method_call(
716 [asyncResp, username,
717 ldapServerElementName](const boost::system::error_code ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700718 if (ec)
719 {
720 BMCWEB_LOG_DEBUG << "Error occurred in updating the username";
721 messages::internalError(asyncResp->res);
722 return;
723 }
724 asyncResp->res
725 .jsonValue[ldapServerElementName]["Authentication"]["Username"] =
726 username;
727 BMCWEB_LOG_DEBUG << "Updated the username";
Ed Tanous6c51eab2021-06-03 12:30:29 -0700728 },
729 ldapDbusService, ldapConfigObject, propertyInterface, "Set",
Ed Tanous168e20c2021-12-13 14:39:53 -0800730 ldapConfigInterface, "LDAPBindDN",
731 dbus::utility::DbusVariantType(username));
Ed Tanous6c51eab2021-06-03 12:30:29 -0700732}
733
734/**
735 * @brief updates the LDAP password
736 * @param password : ldap password which needs to be updated.
737 * @param asyncResp pointer to the JSON response
738 * @param ldapServerElementName Type of LDAP
739 * server(openLDAP/ActiveDirectory)
740 */
741
Ed Tanous4f48d5f2021-06-21 08:27:45 -0700742inline void
743 handlePasswordPatch(const std::string& password,
744 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
745 const std::string& ldapServerElementName,
746 const std::string& ldapConfigObject)
Ed Tanous6c51eab2021-06-03 12:30:29 -0700747{
748 crow::connections::systemBus->async_method_call(
749 [asyncResp, password,
750 ldapServerElementName](const boost::system::error_code ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700751 if (ec)
752 {
753 BMCWEB_LOG_DEBUG << "Error occurred in updating the password";
754 messages::internalError(asyncResp->res);
755 return;
756 }
757 asyncResp->res
758 .jsonValue[ldapServerElementName]["Authentication"]["Password"] =
759 "";
760 BMCWEB_LOG_DEBUG << "Updated the password";
Ed Tanous6c51eab2021-06-03 12:30:29 -0700761 },
762 ldapDbusService, ldapConfigObject, propertyInterface, "Set",
763 ldapConfigInterface, "LDAPBindDNPassword",
Ed Tanous168e20c2021-12-13 14:39:53 -0800764 dbus::utility::DbusVariantType(password));
Ed Tanous6c51eab2021-06-03 12:30:29 -0700765}
766
767/**
768 * @brief updates the LDAP BaseDN and updates the
769 json response with the new value.
770 * @param baseDNList baseDN list which needs to be updated.
771 * @param asyncResp pointer to the JSON response
772 * @param ldapServerElementName Type of LDAP
773 server(openLDAP/ActiveDirectory)
774 */
775
Ed Tanous4f48d5f2021-06-21 08:27:45 -0700776inline void
777 handleBaseDNPatch(const std::vector<std::string>& baseDNList,
778 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
779 const std::string& ldapServerElementName,
780 const std::string& ldapConfigObject)
Ed Tanous6c51eab2021-06-03 12:30:29 -0700781{
782 crow::connections::systemBus->async_method_call(
783 [asyncResp, baseDNList,
784 ldapServerElementName](const boost::system::error_code ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700785 if (ec)
786 {
787 BMCWEB_LOG_DEBUG << "Error Occurred in Updating the base DN";
788 messages::internalError(asyncResp->res);
789 return;
790 }
791 auto& serverTypeJson = asyncResp->res.jsonValue[ldapServerElementName];
792 auto& searchSettingsJson =
793 serverTypeJson["LDAPService"]["SearchSettings"];
794 std::vector<std::string> modifiedBaseDNList = {baseDNList.front()};
795 searchSettingsJson["BaseDistinguishedNames"] = modifiedBaseDNList;
796 if (baseDNList.size() > 1)
797 {
798 messages::propertyValueModified(
799 asyncResp->res, "BaseDistinguishedNames", baseDNList.front());
800 }
801 BMCWEB_LOG_DEBUG << "Updated the base DN";
Ed Tanous6c51eab2021-06-03 12:30:29 -0700802 },
803 ldapDbusService, ldapConfigObject, propertyInterface, "Set",
804 ldapConfigInterface, "LDAPBaseDN",
Ed Tanous168e20c2021-12-13 14:39:53 -0800805 dbus::utility::DbusVariantType(baseDNList.front()));
Ed Tanous6c51eab2021-06-03 12:30:29 -0700806}
807/**
808 * @brief updates the LDAP user name attribute and updates the
809 json response with the new value.
810 * @param userNameAttribute attribute to be updated.
811 * @param asyncResp pointer to the JSON response
812 * @param ldapServerElementName Type of LDAP
813 server(openLDAP/ActiveDirectory)
814 */
815
Ed Tanous4f48d5f2021-06-21 08:27:45 -0700816inline void
817 handleUserNameAttrPatch(const std::string& userNameAttribute,
818 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
819 const std::string& ldapServerElementName,
820 const std::string& ldapConfigObject)
Ed Tanous6c51eab2021-06-03 12:30:29 -0700821{
822 crow::connections::systemBus->async_method_call(
823 [asyncResp, userNameAttribute,
824 ldapServerElementName](const boost::system::error_code ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700825 if (ec)
826 {
827 BMCWEB_LOG_DEBUG << "Error Occurred in Updating the "
828 "username attribute";
829 messages::internalError(asyncResp->res);
830 return;
831 }
832 auto& serverTypeJson = asyncResp->res.jsonValue[ldapServerElementName];
833 auto& searchSettingsJson =
834 serverTypeJson["LDAPService"]["SearchSettings"];
835 searchSettingsJson["UsernameAttribute"] = userNameAttribute;
836 BMCWEB_LOG_DEBUG << "Updated the user name attr.";
Ed Tanous6c51eab2021-06-03 12:30:29 -0700837 },
838 ldapDbusService, ldapConfigObject, propertyInterface, "Set",
839 ldapConfigInterface, "UserNameAttribute",
Ed Tanous168e20c2021-12-13 14:39:53 -0800840 dbus::utility::DbusVariantType(userNameAttribute));
Ed Tanous6c51eab2021-06-03 12:30:29 -0700841}
842/**
843 * @brief updates the LDAP group attribute and updates the
844 json response with the new value.
845 * @param groupsAttribute attribute to be updated.
846 * @param asyncResp pointer to the JSON response
847 * @param ldapServerElementName Type of LDAP
848 server(openLDAP/ActiveDirectory)
849 */
850
Ed Tanous4f48d5f2021-06-21 08:27:45 -0700851inline void handleGroupNameAttrPatch(
Ed Tanous6c51eab2021-06-03 12:30:29 -0700852 const std::string& groupsAttribute,
853 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
854 const std::string& ldapServerElementName,
855 const std::string& ldapConfigObject)
856{
857 crow::connections::systemBus->async_method_call(
858 [asyncResp, groupsAttribute,
859 ldapServerElementName](const boost::system::error_code ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700860 if (ec)
861 {
862 BMCWEB_LOG_DEBUG << "Error Occurred in Updating the "
863 "groupname attribute";
864 messages::internalError(asyncResp->res);
865 return;
866 }
867 auto& serverTypeJson = asyncResp->res.jsonValue[ldapServerElementName];
868 auto& searchSettingsJson =
869 serverTypeJson["LDAPService"]["SearchSettings"];
870 searchSettingsJson["GroupsAttribute"] = groupsAttribute;
871 BMCWEB_LOG_DEBUG << "Updated the groupname attr";
Ed Tanous6c51eab2021-06-03 12:30:29 -0700872 },
873 ldapDbusService, ldapConfigObject, propertyInterface, "Set",
874 ldapConfigInterface, "GroupNameAttribute",
Ed Tanous168e20c2021-12-13 14:39:53 -0800875 dbus::utility::DbusVariantType(groupsAttribute));
Ed Tanous6c51eab2021-06-03 12:30:29 -0700876}
877/**
878 * @brief updates the LDAP service enable and updates the
879 json response with the new value.
880 * @param input JSON data.
881 * @param asyncResp pointer to the JSON response
882 * @param ldapServerElementName Type of LDAP
883 server(openLDAP/ActiveDirectory)
884 */
885
Ed Tanous4f48d5f2021-06-21 08:27:45 -0700886inline void handleServiceEnablePatch(
Ed Tanous6c51eab2021-06-03 12:30:29 -0700887 bool serviceEnabled, const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
888 const std::string& ldapServerElementName,
889 const std::string& ldapConfigObject)
890{
891 crow::connections::systemBus->async_method_call(
892 [asyncResp, serviceEnabled,
893 ldapServerElementName](const boost::system::error_code ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700894 if (ec)
895 {
896 BMCWEB_LOG_DEBUG << "Error Occurred in Updating the service enable";
897 messages::internalError(asyncResp->res);
898 return;
899 }
900 asyncResp->res.jsonValue[ldapServerElementName]["ServiceEnabled"] =
901 serviceEnabled;
902 BMCWEB_LOG_DEBUG << "Updated Service enable = " << serviceEnabled;
Ed Tanous6c51eab2021-06-03 12:30:29 -0700903 },
904 ldapDbusService, ldapConfigObject, propertyInterface, "Set",
Ed Tanous168e20c2021-12-13 14:39:53 -0800905 ldapEnableInterface, "Enabled",
906 dbus::utility::DbusVariantType(serviceEnabled));
Ed Tanous6c51eab2021-06-03 12:30:29 -0700907}
908
Ed Tanous4f48d5f2021-06-21 08:27:45 -0700909inline void
910 handleAuthMethodsPatch(nlohmann::json& input,
911 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Ed Tanous6c51eab2021-06-03 12:30:29 -0700912{
913 std::optional<bool> basicAuth;
914 std::optional<bool> cookie;
915 std::optional<bool> sessionToken;
916 std::optional<bool> xToken;
917 std::optional<bool> tls;
918
919 if (!json_util::readJson(input, asyncResp->res, "BasicAuth", basicAuth,
920 "Cookie", cookie, "SessionToken", sessionToken,
921 "XToken", xToken, "TLS", tls))
Ratan Gupta8a07d282019-03-16 08:33:47 +0530922 {
Ed Tanous6c51eab2021-06-03 12:30:29 -0700923 BMCWEB_LOG_ERROR << "Cannot read values from AuthMethod tag";
924 return;
925 }
926
927 // Make a copy of methods configuration
928 persistent_data::AuthConfigMethods authMethodsConfig =
929 persistent_data::SessionStore::getInstance().getAuthMethodsConfig();
930
931 if (basicAuth)
932 {
933#ifndef BMCWEB_ENABLE_BASIC_AUTHENTICATION
934 messages::actionNotSupported(
George Liu0fda0f12021-11-16 10:06:17 +0800935 asyncResp->res,
936 "Setting BasicAuth when basic-auth feature is disabled");
Ed Tanous6c51eab2021-06-03 12:30:29 -0700937 return;
938#endif
939 authMethodsConfig.basic = *basicAuth;
940 }
941
942 if (cookie)
943 {
944#ifndef BMCWEB_ENABLE_COOKIE_AUTHENTICATION
George Liu0fda0f12021-11-16 10:06:17 +0800945 messages::actionNotSupported(
946 asyncResp->res,
947 "Setting Cookie when cookie-auth feature is disabled");
Ed Tanous6c51eab2021-06-03 12:30:29 -0700948 return;
949#endif
950 authMethodsConfig.cookie = *cookie;
951 }
952
953 if (sessionToken)
954 {
955#ifndef BMCWEB_ENABLE_SESSION_AUTHENTICATION
956 messages::actionNotSupported(
George Liu0fda0f12021-11-16 10:06:17 +0800957 asyncResp->res,
958 "Setting SessionToken when session-auth feature is disabled");
Ed Tanous6c51eab2021-06-03 12:30:29 -0700959 return;
960#endif
961 authMethodsConfig.sessionToken = *sessionToken;
962 }
963
964 if (xToken)
965 {
966#ifndef BMCWEB_ENABLE_XTOKEN_AUTHENTICATION
George Liu0fda0f12021-11-16 10:06:17 +0800967 messages::actionNotSupported(
968 asyncResp->res,
969 "Setting XToken when xtoken-auth feature is disabled");
Ed Tanous6c51eab2021-06-03 12:30:29 -0700970 return;
971#endif
972 authMethodsConfig.xtoken = *xToken;
973 }
974
975 if (tls)
976 {
977#ifndef BMCWEB_ENABLE_MUTUAL_TLS_AUTHENTICATION
George Liu0fda0f12021-11-16 10:06:17 +0800978 messages::actionNotSupported(
979 asyncResp->res,
980 "Setting TLS when mutual-tls-auth feature is disabled");
Ed Tanous6c51eab2021-06-03 12:30:29 -0700981 return;
982#endif
983 authMethodsConfig.tls = *tls;
984 }
985
986 if (!authMethodsConfig.basic && !authMethodsConfig.cookie &&
987 !authMethodsConfig.sessionToken && !authMethodsConfig.xtoken &&
988 !authMethodsConfig.tls)
989 {
990 // Do not allow user to disable everything
991 messages::actionNotSupported(asyncResp->res,
992 "of disabling all available methods");
993 return;
994 }
995
996 persistent_data::SessionStore::getInstance().updateAuthMethodsConfig(
997 authMethodsConfig);
998 // Save configuration immediately
999 persistent_data::getConfig().writeData();
1000
1001 messages::success(asyncResp->res);
1002}
1003
1004/**
1005 * @brief Get the required values from the given JSON, validates the
1006 * value and create the LDAP config object.
1007 * @param input JSON data
1008 * @param asyncResp pointer to the JSON response
1009 * @param serverType Type of LDAP server(openLDAP/ActiveDirectory)
1010 */
1011
1012inline void handleLDAPPatch(nlohmann::json& input,
1013 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1014 const std::string& serverType)
1015{
1016 std::string dbusObjectPath;
1017 if (serverType == "ActiveDirectory")
1018 {
1019 dbusObjectPath = adConfigObject;
1020 }
1021 else if (serverType == "LDAP")
1022 {
1023 dbusObjectPath = ldapConfigObjectName;
1024 }
1025 else
1026 {
1027 return;
1028 }
1029
1030 std::optional<nlohmann::json> authentication;
1031 std::optional<nlohmann::json> ldapService;
1032 std::optional<std::vector<std::string>> serviceAddressList;
1033 std::optional<bool> serviceEnabled;
1034 std::optional<std::vector<std::string>> baseDNList;
1035 std::optional<std::string> userNameAttribute;
1036 std::optional<std::string> groupsAttribute;
1037 std::optional<std::string> userName;
1038 std::optional<std::string> password;
1039 std::optional<std::vector<nlohmann::json>> remoteRoleMapData;
1040
1041 if (!json_util::readJson(input, asyncResp->res, "Authentication",
1042 authentication, "LDAPService", ldapService,
1043 "ServiceAddresses", serviceAddressList,
1044 "ServiceEnabled", serviceEnabled,
1045 "RemoteRoleMapping", remoteRoleMapData))
1046 {
1047 return;
1048 }
1049
1050 if (authentication)
1051 {
1052 parseLDAPAuthenticationJson(*authentication, asyncResp, userName,
1053 password);
1054 }
1055 if (ldapService)
1056 {
1057 parseLDAPServiceJson(*ldapService, asyncResp, baseDNList,
1058 userNameAttribute, groupsAttribute);
1059 }
1060 if (serviceAddressList)
1061 {
Ed Tanous26f69762022-01-25 09:49:11 -08001062 if (serviceAddressList->empty())
Ratan Guptaeb2bbe52019-04-22 14:27:01 +05301063 {
Ed Tanous6c51eab2021-06-03 12:30:29 -07001064 messages::propertyValueNotInList(asyncResp->res, "[]",
1065 "ServiceAddress");
Ed Tanouscb13a392020-07-25 19:02:03 +00001066 return;
1067 }
Ed Tanous6c51eab2021-06-03 12:30:29 -07001068 }
1069 if (baseDNList)
1070 {
Ed Tanous26f69762022-01-25 09:49:11 -08001071 if (baseDNList->empty())
Ratan Gupta8a07d282019-03-16 08:33:47 +05301072 {
Ed Tanous6c51eab2021-06-03 12:30:29 -07001073 messages::propertyValueNotInList(asyncResp->res, "[]",
1074 "BaseDistinguishedNames");
Ratan Gupta8a07d282019-03-16 08:33:47 +05301075 return;
1076 }
Ed Tanous6c51eab2021-06-03 12:30:29 -07001077 }
Ratan Gupta8a07d282019-03-16 08:33:47 +05301078
Ed Tanous6c51eab2021-06-03 12:30:29 -07001079 // nothing to update, then return
1080 if (!userName && !password && !serviceAddressList && !baseDNList &&
1081 !userNameAttribute && !groupsAttribute && !serviceEnabled &&
1082 !remoteRoleMapData)
1083 {
1084 return;
1085 }
1086
1087 // Get the existing resource first then keep modifying
1088 // whenever any property gets updated.
Ed Tanous002d39b2022-05-31 08:59:27 -07001089 getLDAPConfigData(
1090 serverType,
1091 [asyncResp, userName, password, baseDNList, userNameAttribute,
1092 groupsAttribute, serviceAddressList, serviceEnabled, dbusObjectPath,
1093 remoteRoleMapData](bool success, const LDAPConfigData& confData,
1094 const std::string& serverT) {
Ed Tanous6c51eab2021-06-03 12:30:29 -07001095 if (!success)
Ratan Gupta8a07d282019-03-16 08:33:47 +05301096 {
Ed Tanous6c51eab2021-06-03 12:30:29 -07001097 messages::internalError(asyncResp->res);
1098 return;
Ratan Gupta8a07d282019-03-16 08:33:47 +05301099 }
Ed Tanous6c51eab2021-06-03 12:30:29 -07001100 parseLDAPConfigData(asyncResp->res.jsonValue, confData, serverT);
1101 if (confData.serviceEnabled)
Ratan Gupta8a07d282019-03-16 08:33:47 +05301102 {
Ed Tanous6c51eab2021-06-03 12:30:29 -07001103 // Disable the service first and update the rest of
1104 // the properties.
1105 handleServiceEnablePatch(false, asyncResp, serverT, dbusObjectPath);
Ratan Gupta8a07d282019-03-16 08:33:47 +05301106 }
Ed Tanous6c51eab2021-06-03 12:30:29 -07001107
Ratan Gupta8a07d282019-03-16 08:33:47 +05301108 if (serviceAddressList)
1109 {
Ed Tanous6c51eab2021-06-03 12:30:29 -07001110 handleServiceAddressPatch(*serviceAddressList, asyncResp, serverT,
1111 dbusObjectPath);
Ratan Gupta8a07d282019-03-16 08:33:47 +05301112 }
Ed Tanous6c51eab2021-06-03 12:30:29 -07001113 if (userName)
1114 {
1115 handleUserNamePatch(*userName, asyncResp, serverT, dbusObjectPath);
1116 }
1117 if (password)
1118 {
1119 handlePasswordPatch(*password, asyncResp, serverT, dbusObjectPath);
1120 }
1121
Ratan Gupta8a07d282019-03-16 08:33:47 +05301122 if (baseDNList)
1123 {
Ed Tanous6c51eab2021-06-03 12:30:29 -07001124 handleBaseDNPatch(*baseDNList, asyncResp, serverT, dbusObjectPath);
1125 }
1126 if (userNameAttribute)
1127 {
1128 handleUserNameAttrPatch(*userNameAttribute, asyncResp, serverT,
1129 dbusObjectPath);
1130 }
1131 if (groupsAttribute)
1132 {
1133 handleGroupNameAttrPatch(*groupsAttribute, asyncResp, serverT,
1134 dbusObjectPath);
1135 }
1136 if (serviceEnabled)
1137 {
1138 // if user has given the value as true then enable
1139 // the service. if user has given false then no-op
1140 // as service is already stopped.
1141 if (*serviceEnabled)
Ratan Gupta8a07d282019-03-16 08:33:47 +05301142 {
Ed Tanous6c51eab2021-06-03 12:30:29 -07001143 handleServiceEnablePatch(*serviceEnabled, asyncResp, serverT,
1144 dbusObjectPath);
Ratan Gupta8a07d282019-03-16 08:33:47 +05301145 }
1146 }
jayaprakash Mutyala96200602020-04-08 11:09:10 +00001147 else
1148 {
Ed Tanous6c51eab2021-06-03 12:30:29 -07001149 // if user has not given the service enabled value
1150 // then revert it to the same state as it was
1151 // before.
1152 handleServiceEnablePatch(confData.serviceEnabled, asyncResp,
1153 serverT, dbusObjectPath);
jayaprakash Mutyala96200602020-04-08 11:09:10 +00001154 }
Ed Tanous04ae99e2018-09-20 15:54:36 -07001155
Ed Tanous6c51eab2021-06-03 12:30:29 -07001156 if (remoteRoleMapData)
1157 {
1158 handleRoleMapPatch(asyncResp, confData.groupRoleList, serverT,
1159 *remoteRoleMapData);
1160 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001161 });
Ed Tanous6c51eab2021-06-03 12:30:29 -07001162}
1163
1164inline void updateUserProperties(std::shared_ptr<bmcweb::AsyncResp> asyncResp,
1165 const std::string& username,
1166 std::optional<std::string> password,
1167 std::optional<bool> enabled,
1168 std::optional<std::string> roleId,
1169 std::optional<bool> locked)
1170{
P Dheeraj Srujan Kumarb477fd42021-12-16 07:17:51 +05301171 sdbusplus::message::object_path tempObjPath(rootUserDbusPath);
1172 tempObjPath /= username;
1173 std::string dbusObjectPath(tempObjPath);
Ed Tanous6c51eab2021-06-03 12:30:29 -07001174
1175 dbus::utility::checkDbusPathExists(
1176 dbusObjectPath,
Ed Tanous11063332021-09-24 11:55:44 -07001177 [dbusObjectPath, username, password(std::move(password)),
1178 roleId(std::move(roleId)), enabled, locked,
1179 asyncResp{std::move(asyncResp)}](int rc) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001180 if (rc <= 0)
1181 {
Jiaqing Zhaod8a5d5d2022-08-05 16:21:51 +08001182 messages::resourceNotFound(asyncResp->res, "ManagerAccount",
Ed Tanous002d39b2022-05-31 08:59:27 -07001183 username);
1184 return;
1185 }
1186
1187 if (password)
1188 {
1189 int retval = pamUpdatePassword(username, *password);
1190
1191 if (retval == PAM_USER_UNKNOWN)
Ed Tanous6c51eab2021-06-03 12:30:29 -07001192 {
Jiaqing Zhaod8a5d5d2022-08-05 16:21:51 +08001193 messages::resourceNotFound(asyncResp->res, "ManagerAccount",
1194 username);
Ed Tanous002d39b2022-05-31 08:59:27 -07001195 }
1196 else if (retval == PAM_AUTHTOK_ERR)
1197 {
1198 // If password is invalid
1199 messages::propertyValueFormatError(asyncResp->res, *password,
1200 "Password");
1201 BMCWEB_LOG_ERROR << "pamUpdatePassword Failed";
1202 }
1203 else if (retval != PAM_SUCCESS)
1204 {
1205 messages::internalError(asyncResp->res);
Ed Tanous6c51eab2021-06-03 12:30:29 -07001206 return;
1207 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001208 else
Ed Tanous6c51eab2021-06-03 12:30:29 -07001209 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001210 messages::success(asyncResp->res);
1211 }
1212 }
Ed Tanous6c51eab2021-06-03 12:30:29 -07001213
Ed Tanous002d39b2022-05-31 08:59:27 -07001214 if (enabled)
1215 {
1216 crow::connections::systemBus->async_method_call(
1217 [asyncResp](const boost::system::error_code ec) {
1218 if (ec)
Ed Tanous04ae99e2018-09-20 15:54:36 -07001219 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001220 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
Ayushi Smriti599c71d2019-08-23 17:43:18 +00001221 messages::internalError(asyncResp->res);
Ed Tanous04ae99e2018-09-20 15:54:36 -07001222 return;
1223 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001224 messages::success(asyncResp->res);
1225 return;
1226 },
1227 "xyz.openbmc_project.User.Manager", dbusObjectPath,
1228 "org.freedesktop.DBus.Properties", "Set",
1229 "xyz.openbmc_project.User.Attributes", "UserEnabled",
1230 dbus::utility::DbusVariantType{*enabled});
1231 }
1232
1233 if (roleId)
1234 {
1235 std::string priv = getPrivilegeFromRoleId(*roleId);
1236 if (priv.empty())
1237 {
1238 messages::propertyValueNotInList(asyncResp->res, *roleId,
1239 "RoleId");
1240 return;
1241 }
Ed Tanous04ae99e2018-09-20 15:54:36 -07001242
Ed Tanous002d39b2022-05-31 08:59:27 -07001243 crow::connections::systemBus->async_method_call(
1244 [asyncResp](const boost::system::error_code ec) {
1245 if (ec)
Ed Tanous04ae99e2018-09-20 15:54:36 -07001246 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001247 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
1248 messages::internalError(asyncResp->res);
Ed Tanous6c51eab2021-06-03 12:30:29 -07001249 return;
1250 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001251 messages::success(asyncResp->res);
1252 },
1253 "xyz.openbmc_project.User.Manager", dbusObjectPath,
1254 "org.freedesktop.DBus.Properties", "Set",
1255 "xyz.openbmc_project.User.Attributes", "UserPrivilege",
1256 dbus::utility::DbusVariantType{priv});
1257 }
Ed Tanous6c51eab2021-06-03 12:30:29 -07001258
Ed Tanous002d39b2022-05-31 08:59:27 -07001259 if (locked)
1260 {
1261 // admin can unlock the account which is locked by
1262 // successive authentication failures but admin should
1263 // not be allowed to lock an account.
1264 if (*locked)
1265 {
1266 messages::propertyValueNotInList(asyncResp->res, "true",
1267 "Locked");
1268 return;
Ed Tanous6c51eab2021-06-03 12:30:29 -07001269 }
1270
Ed Tanous002d39b2022-05-31 08:59:27 -07001271 crow::connections::systemBus->async_method_call(
1272 [asyncResp](const boost::system::error_code ec) {
1273 if (ec)
Ed Tanous6c51eab2021-06-03 12:30:29 -07001274 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001275 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
1276 messages::internalError(asyncResp->res);
Ed Tanous04ae99e2018-09-20 15:54:36 -07001277 return;
1278 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001279 messages::success(asyncResp->res);
1280 return;
1281 },
1282 "xyz.openbmc_project.User.Manager", dbusObjectPath,
1283 "org.freedesktop.DBus.Properties", "Set",
1284 "xyz.openbmc_project.User.Attributes",
1285 "UserLockedForFailedAttempt",
1286 dbus::utility::DbusVariantType{*locked});
1287 }
Ed Tanous6c51eab2021-06-03 12:30:29 -07001288 });
1289}
Ed Tanousb9b2e0b2018-09-13 13:47:50 -07001290
Ed Tanous4c7d4d32022-07-07 15:29:35 -07001291inline void handleAccountServiceHead(
1292 App& app, const crow::Request& req,
1293 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Ed Tanous1ef4c342022-05-12 16:12:36 -07001294{
Ed Tanous4c7d4d32022-07-07 15:29:35 -07001295
Ed Tanous1ef4c342022-05-12 16:12:36 -07001296 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1297 {
1298 return;
1299 }
Ed Tanous4c7d4d32022-07-07 15:29:35 -07001300 asyncResp->res.addHeader(
1301 boost::beast::http::field::link,
1302 "</redfish/v1/JsonSchemas/AccountService/AccountService.json>; rel=describedby");
1303}
1304
1305inline void
1306 handleAccountServiceGet(App& app, const crow::Request& req,
1307 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1308{
1309 handleAccountServiceHead(app, req, asyncResp);
Ed Tanous1ef4c342022-05-12 16:12:36 -07001310 const persistent_data::AuthConfigMethods& authMethodsConfig =
1311 persistent_data::SessionStore::getInstance().getAuthMethodsConfig();
1312
1313 nlohmann::json& json = asyncResp->res.jsonValue;
1314 json["@odata.id"] = "/redfish/v1/AccountService";
1315 json["@odata.type"] = "#AccountService."
1316 "v1_10_0.AccountService";
1317 json["Id"] = "AccountService";
1318 json["Name"] = "Account Service";
1319 json["Description"] = "Account Service";
1320 json["ServiceEnabled"] = true;
1321 json["MaxPasswordLength"] = 20;
1322 json["Accounts"]["@odata.id"] = "/redfish/v1/AccountService/Accounts";
1323 json["Roles"]["@odata.id"] = "/redfish/v1/AccountService/Roles";
1324 json["Oem"]["OpenBMC"]["@odata.type"] =
1325 "#OemAccountService.v1_0_0.AccountService";
1326 json["Oem"]["OpenBMC"]["@odata.id"] =
1327 "/redfish/v1/AccountService#/Oem/OpenBMC";
1328 json["Oem"]["OpenBMC"]["AuthMethods"]["BasicAuth"] =
1329 authMethodsConfig.basic;
1330 json["Oem"]["OpenBMC"]["AuthMethods"]["SessionToken"] =
1331 authMethodsConfig.sessionToken;
1332 json["Oem"]["OpenBMC"]["AuthMethods"]["XToken"] = authMethodsConfig.xtoken;
1333 json["Oem"]["OpenBMC"]["AuthMethods"]["Cookie"] = authMethodsConfig.cookie;
1334 json["Oem"]["OpenBMC"]["AuthMethods"]["TLS"] = authMethodsConfig.tls;
1335
1336 // /redfish/v1/AccountService/LDAP/Certificates is something only
1337 // ConfigureManager can access then only display when the user has
1338 // permissions ConfigureManager
1339 Privileges effectiveUserPrivileges =
1340 redfish::getUserPrivileges(req.userRole);
1341
1342 if (isOperationAllowedWithPrivileges({{"ConfigureManager"}},
1343 effectiveUserPrivileges))
1344 {
1345 asyncResp->res.jsonValue["LDAP"]["Certificates"]["@odata.id"] =
1346 "/redfish/v1/AccountService/LDAP/Certificates";
1347 }
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001348 sdbusplus::asio::getAllProperties(
1349 *crow::connections::systemBus, "xyz.openbmc_project.User.Manager",
1350 "/xyz/openbmc_project/user", "xyz.openbmc_project.User.AccountPolicy",
Ed Tanous1ef4c342022-05-12 16:12:36 -07001351 [asyncResp](const boost::system::error_code ec,
1352 const dbus::utility::DBusPropertiesMap& propertiesList) {
1353 if (ec)
1354 {
1355 messages::internalError(asyncResp->res);
1356 return;
1357 }
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001358
Ed Tanous1ef4c342022-05-12 16:12:36 -07001359 BMCWEB_LOG_DEBUG << "Got " << propertiesList.size()
1360 << "properties for AccountService";
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001361
1362 const uint8_t* minPasswordLength = nullptr;
1363 const uint32_t* accountUnlockTimeout = nullptr;
1364 const uint16_t* maxLoginAttemptBeforeLockout = nullptr;
1365
1366 const bool success = sdbusplus::unpackPropertiesNoThrow(
1367 dbus_utils::UnpackErrorPrinter(), propertiesList,
1368 "MinPasswordLength", minPasswordLength, "AccountUnlockTimeout",
1369 accountUnlockTimeout, "MaxLoginAttemptBeforeLockout",
1370 maxLoginAttemptBeforeLockout);
1371
1372 if (!success)
Ed Tanous1ef4c342022-05-12 16:12:36 -07001373 {
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001374 messages::internalError(asyncResp->res);
1375 return;
Ed Tanous1ef4c342022-05-12 16:12:36 -07001376 }
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001377
1378 if (minPasswordLength != nullptr)
1379 {
1380 asyncResp->res.jsonValue["MinPasswordLength"] = *minPasswordLength;
1381 }
1382
1383 if (accountUnlockTimeout != nullptr)
1384 {
1385 asyncResp->res.jsonValue["AccountLockoutDuration"] =
1386 *accountUnlockTimeout;
1387 }
1388
1389 if (maxLoginAttemptBeforeLockout != nullptr)
1390 {
1391 asyncResp->res.jsonValue["AccountLockoutThreshold"] =
1392 *maxLoginAttemptBeforeLockout;
1393 }
1394 });
Ed Tanous1ef4c342022-05-12 16:12:36 -07001395
Ed Tanous02cad962022-06-30 16:50:15 -07001396 auto callback = [asyncResp](bool success, const LDAPConfigData& confData,
Ed Tanous1ef4c342022-05-12 16:12:36 -07001397 const std::string& ldapType) {
1398 if (!success)
1399 {
1400 return;
1401 }
1402 parseLDAPConfigData(asyncResp->res.jsonValue, confData, ldapType);
1403 };
1404
1405 getLDAPConfigData("LDAP", callback);
1406 getLDAPConfigData("ActiveDirectory", callback);
1407}
1408
1409inline void handleAccountServicePatch(
1410 App& app, const crow::Request& req,
1411 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1412{
1413 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1414 {
1415 return;
1416 }
1417 std::optional<uint32_t> unlockTimeout;
1418 std::optional<uint16_t> lockoutThreshold;
1419 std::optional<uint8_t> minPasswordLength;
1420 std::optional<uint16_t> maxPasswordLength;
1421 std::optional<nlohmann::json> ldapObject;
1422 std::optional<nlohmann::json> activeDirectoryObject;
1423 std::optional<nlohmann::json> oemObject;
1424
1425 if (!json_util::readJsonPatch(
1426 req, asyncResp->res, "AccountLockoutDuration", unlockTimeout,
1427 "AccountLockoutThreshold", lockoutThreshold, "MaxPasswordLength",
1428 maxPasswordLength, "MinPasswordLength", minPasswordLength, "LDAP",
1429 ldapObject, "ActiveDirectory", activeDirectoryObject, "Oem",
1430 oemObject))
1431 {
1432 return;
1433 }
1434
1435 if (minPasswordLength)
1436 {
1437 crow::connections::systemBus->async_method_call(
1438 [asyncResp](const boost::system::error_code ec) {
1439 if (ec)
1440 {
1441 messages::internalError(asyncResp->res);
1442 return;
1443 }
1444 messages::success(asyncResp->res);
1445 },
1446 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
1447 "org.freedesktop.DBus.Properties", "Set",
1448 "xyz.openbmc_project.User.AccountPolicy", "MinPasswordLength",
1449 dbus::utility::DbusVariantType(*minPasswordLength));
1450 }
1451
1452 if (maxPasswordLength)
1453 {
1454 messages::propertyNotWritable(asyncResp->res, "MaxPasswordLength");
1455 }
1456
1457 if (ldapObject)
1458 {
1459 handleLDAPPatch(*ldapObject, asyncResp, "LDAP");
1460 }
1461
1462 if (std::optional<nlohmann::json> oemOpenBMCObject;
1463 oemObject && json_util::readJson(*oemObject, asyncResp->res, "OpenBMC",
1464 oemOpenBMCObject))
1465 {
1466 if (std::optional<nlohmann::json> authMethodsObject;
1467 oemOpenBMCObject &&
1468 json_util::readJson(*oemOpenBMCObject, asyncResp->res,
1469 "AuthMethods", authMethodsObject))
1470 {
1471 if (authMethodsObject)
1472 {
1473 handleAuthMethodsPatch(*authMethodsObject, asyncResp);
1474 }
1475 }
1476 }
1477
1478 if (activeDirectoryObject)
1479 {
1480 handleLDAPPatch(*activeDirectoryObject, asyncResp, "ActiveDirectory");
1481 }
1482
1483 if (unlockTimeout)
1484 {
1485 crow::connections::systemBus->async_method_call(
1486 [asyncResp](const boost::system::error_code ec) {
1487 if (ec)
1488 {
1489 messages::internalError(asyncResp->res);
1490 return;
1491 }
1492 messages::success(asyncResp->res);
1493 },
1494 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
1495 "org.freedesktop.DBus.Properties", "Set",
1496 "xyz.openbmc_project.User.AccountPolicy", "AccountUnlockTimeout",
1497 dbus::utility::DbusVariantType(*unlockTimeout));
1498 }
1499 if (lockoutThreshold)
1500 {
1501 crow::connections::systemBus->async_method_call(
1502 [asyncResp](const boost::system::error_code ec) {
1503 if (ec)
1504 {
1505 messages::internalError(asyncResp->res);
1506 return;
1507 }
1508 messages::success(asyncResp->res);
1509 },
1510 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
1511 "org.freedesktop.DBus.Properties", "Set",
1512 "xyz.openbmc_project.User.AccountPolicy",
1513 "MaxLoginAttemptBeforeLockout",
1514 dbus::utility::DbusVariantType(*lockoutThreshold));
1515 }
1516}
1517
Ed Tanous4c7d4d32022-07-07 15:29:35 -07001518inline void handleAccountCollectionHead(
Ed Tanous1ef4c342022-05-12 16:12:36 -07001519 App& app, const crow::Request& req,
1520 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1521{
Ed Tanous4c7d4d32022-07-07 15:29:35 -07001522
Ed Tanous1ef4c342022-05-12 16:12:36 -07001523 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1524 {
1525 return;
1526 }
Ed Tanous4c7d4d32022-07-07 15:29:35 -07001527 asyncResp->res.addHeader(
1528 boost::beast::http::field::link,
1529 "</redfish/v1/JsonSchemas/ManagerAccountCollection.json>; rel=describedby");
1530}
1531
1532inline void handleAccountCollectionGet(
1533 App& app, const crow::Request& req,
1534 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1535{
1536 handleAccountCollectionHead(app, req, asyncResp);
Ed Tanous1ef4c342022-05-12 16:12:36 -07001537
1538 asyncResp->res.jsonValue["@odata.id"] =
1539 "/redfish/v1/AccountService/Accounts";
1540 asyncResp->res.jsonValue["@odata.type"] = "#ManagerAccountCollection."
1541 "ManagerAccountCollection";
1542 asyncResp->res.jsonValue["Name"] = "Accounts Collection";
1543 asyncResp->res.jsonValue["Description"] = "BMC User Accounts";
1544
1545 Privileges effectiveUserPrivileges =
1546 redfish::getUserPrivileges(req.userRole);
1547
1548 std::string thisUser;
1549 if (req.session)
1550 {
1551 thisUser = req.session->username;
1552 }
1553 crow::connections::systemBus->async_method_call(
1554 [asyncResp, thisUser, effectiveUserPrivileges](
1555 const boost::system::error_code ec,
1556 const dbus::utility::ManagedObjectType& users) {
1557 if (ec)
1558 {
1559 messages::internalError(asyncResp->res);
1560 return;
1561 }
1562
1563 bool userCanSeeAllAccounts =
1564 effectiveUserPrivileges.isSupersetOf({"ConfigureUsers"});
1565
1566 bool userCanSeeSelf =
1567 effectiveUserPrivileges.isSupersetOf({"ConfigureSelf"});
1568
1569 nlohmann::json& memberArray = asyncResp->res.jsonValue["Members"];
1570 memberArray = nlohmann::json::array();
1571
1572 for (const auto& userpath : users)
1573 {
1574 std::string user = userpath.first.filename();
1575 if (user.empty())
1576 {
1577 messages::internalError(asyncResp->res);
1578 BMCWEB_LOG_ERROR << "Invalid firmware ID";
1579
1580 return;
1581 }
1582
1583 // As clarified by Redfish here:
1584 // https://redfishforum.com/thread/281/manageraccountcollection-change-allows-account-enumeration
1585 // Users without ConfigureUsers, only see their own
1586 // account. Users with ConfigureUsers, see all
1587 // accounts.
1588 if (userCanSeeAllAccounts || (thisUser == user && userCanSeeSelf))
1589 {
1590 nlohmann::json::object_t member;
1591 member["@odata.id"] =
1592 "/redfish/v1/AccountService/Accounts/" + user;
1593 memberArray.push_back(std::move(member));
1594 }
1595 }
1596 asyncResp->res.jsonValue["Members@odata.count"] = memberArray.size();
1597 },
1598 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
1599 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
1600}
1601
1602inline void handleAccountCollectionPost(
1603 App& app, const crow::Request& req,
1604 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1605{
1606 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1607 {
1608 return;
1609 }
1610 std::string username;
1611 std::string password;
1612 std::optional<std::string> roleId("User");
1613 std::optional<bool> enabled = true;
1614 if (!json_util::readJsonPatch(req, asyncResp->res, "UserName", username,
1615 "Password", password, "RoleId", roleId,
1616 "Enabled", enabled))
1617 {
1618 return;
1619 }
1620
1621 std::string priv = getPrivilegeFromRoleId(*roleId);
1622 if (priv.empty())
1623 {
1624 messages::propertyValueNotInList(asyncResp->res, *roleId, "RoleId");
1625 return;
1626 }
Asmitha Karunanithi239adf82022-03-25 02:59:03 -05001627 roleId = priv;
Ed Tanous1ef4c342022-05-12 16:12:36 -07001628
1629 // Reading AllGroups property
1630 sdbusplus::asio::getProperty<std::vector<std::string>>(
1631 *crow::connections::systemBus, "xyz.openbmc_project.User.Manager",
1632 "/xyz/openbmc_project/user", "xyz.openbmc_project.User.Manager",
1633 "AllGroups",
1634 [asyncResp, username, password{std::move(password)}, roleId,
1635 enabled](const boost::system::error_code ec,
1636 const std::vector<std::string>& allGroupsList) {
1637 if (ec)
1638 {
1639 BMCWEB_LOG_DEBUG << "ERROR with async_method_call";
1640 messages::internalError(asyncResp->res);
1641 return;
1642 }
1643
1644 if (allGroupsList.empty())
1645 {
1646 messages::internalError(asyncResp->res);
1647 return;
1648 }
1649
1650 crow::connections::systemBus->async_method_call(
1651 [asyncResp, username, password](const boost::system::error_code ec2,
Patrick Williams59d494e2022-07-22 19:26:55 -05001652 sdbusplus::message_t& m) {
Ed Tanous1ef4c342022-05-12 16:12:36 -07001653 if (ec2)
1654 {
1655 userErrorMessageHandler(m.get_error(), asyncResp, username, "");
1656 return;
1657 }
1658
1659 if (pamUpdatePassword(username, password) != PAM_SUCCESS)
1660 {
1661 // At this point we have a user that's been
1662 // created, but the password set
1663 // failed.Something is wrong, so delete the user
1664 // that we've already created
1665 sdbusplus::message::object_path tempObjPath(rootUserDbusPath);
1666 tempObjPath /= username;
1667 const std::string userPath(tempObjPath);
1668
1669 crow::connections::systemBus->async_method_call(
1670 [asyncResp, password](const boost::system::error_code ec3) {
1671 if (ec3)
1672 {
1673 messages::internalError(asyncResp->res);
1674 return;
1675 }
1676
1677 // If password is invalid
1678 messages::propertyValueFormatError(asyncResp->res, password,
1679 "Password");
1680 },
1681 "xyz.openbmc_project.User.Manager", userPath,
1682 "xyz.openbmc_project.Object.Delete", "Delete");
1683
1684 BMCWEB_LOG_ERROR << "pamUpdatePassword Failed";
1685 return;
1686 }
1687
1688 messages::created(asyncResp->res);
1689 asyncResp->res.addHeader(
1690 "Location", "/redfish/v1/AccountService/Accounts/" + username);
1691 },
1692 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
1693 "xyz.openbmc_project.User.Manager", "CreateUser", username,
1694 allGroupsList, *roleId, *enabled);
1695 });
1696}
1697
1698inline void
Ed Tanous4c7d4d32022-07-07 15:29:35 -07001699 handleAccountHead(App& app, const crow::Request& req,
1700 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1701 const std::string& /*accountName*/)
Ed Tanous1ef4c342022-05-12 16:12:36 -07001702{
Ed Tanous4c7d4d32022-07-07 15:29:35 -07001703
Ed Tanous1ef4c342022-05-12 16:12:36 -07001704 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1705 {
1706 return;
1707 }
Ed Tanous4c7d4d32022-07-07 15:29:35 -07001708 asyncResp->res.addHeader(
1709 boost::beast::http::field::link,
1710 "</redfish/v1/JsonSchemas/ManagerAccount/ManagerAccount.json>; rel=describedby");
1711}
1712inline void
1713 handleAccountGet(App& app, const crow::Request& req,
1714 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1715 const std::string& accountName)
1716{
1717 handleAccountHead(app, req, asyncResp, accountName);
Ed Tanous1ef4c342022-05-12 16:12:36 -07001718#ifdef BMCWEB_INSECURE_DISABLE_AUTHENTICATION
1719 // If authentication is disabled, there are no user accounts
Jiaqing Zhaod8a5d5d2022-08-05 16:21:51 +08001720 messages::resourceNotFound(asyncResp->res, "ManagerAccount", accountName);
Ed Tanous1ef4c342022-05-12 16:12:36 -07001721 return;
1722
1723#endif // BMCWEB_INSECURE_DISABLE_AUTHENTICATION
1724 if (req.session == nullptr)
1725 {
1726 messages::internalError(asyncResp->res);
1727 return;
1728 }
1729 if (req.session->username != accountName)
1730 {
1731 // At this point we've determined that the user is trying to
1732 // modify a user that isn't them. We need to verify that they
1733 // have permissions to modify other users, so re-run the auth
1734 // check with the same permissions, minus ConfigureSelf.
1735 Privileges effectiveUserPrivileges =
1736 redfish::getUserPrivileges(req.userRole);
1737 Privileges requiredPermissionsToChangeNonSelf = {"ConfigureUsers",
1738 "ConfigureManager"};
1739 if (!effectiveUserPrivileges.isSupersetOf(
1740 requiredPermissionsToChangeNonSelf))
1741 {
1742 BMCWEB_LOG_DEBUG << "GET Account denied access";
1743 messages::insufficientPrivilege(asyncResp->res);
1744 return;
1745 }
1746 }
1747
1748 crow::connections::systemBus->async_method_call(
1749 [asyncResp,
1750 accountName](const boost::system::error_code ec,
1751 const dbus::utility::ManagedObjectType& users) {
1752 if (ec)
1753 {
1754 messages::internalError(asyncResp->res);
1755 return;
1756 }
1757 const auto userIt = std::find_if(
1758 users.begin(), users.end(),
1759 [accountName](
1760 const std::pair<sdbusplus::message::object_path,
1761 dbus::utility::DBusInteracesMap>& user) {
1762 return accountName == user.first.filename();
1763 });
1764
1765 if (userIt == users.end())
1766 {
1767 messages::resourceNotFound(asyncResp->res, "ManagerAccount",
1768 accountName);
1769 return;
1770 }
1771
1772 asyncResp->res.jsonValue["@odata.type"] =
1773 "#ManagerAccount.v1_4_0.ManagerAccount";
1774 asyncResp->res.jsonValue["Name"] = "User Account";
1775 asyncResp->res.jsonValue["Description"] = "User Account";
1776 asyncResp->res.jsonValue["Password"] = nullptr;
Ed Tanous1ef4c342022-05-12 16:12:36 -07001777
1778 for (const auto& interface : userIt->second)
1779 {
1780 if (interface.first == "xyz.openbmc_project.User.Attributes")
1781 {
1782 for (const auto& property : interface.second)
1783 {
1784 if (property.first == "UserEnabled")
1785 {
1786 const bool* userEnabled =
1787 std::get_if<bool>(&property.second);
1788 if (userEnabled == nullptr)
1789 {
1790 BMCWEB_LOG_ERROR << "UserEnabled wasn't a bool";
1791 messages::internalError(asyncResp->res);
1792 return;
1793 }
1794 asyncResp->res.jsonValue["Enabled"] = *userEnabled;
1795 }
1796 else if (property.first == "UserLockedForFailedAttempt")
1797 {
1798 const bool* userLocked =
1799 std::get_if<bool>(&property.second);
1800 if (userLocked == nullptr)
1801 {
1802 BMCWEB_LOG_ERROR << "UserLockedForF"
1803 "ailedAttempt "
1804 "wasn't a bool";
1805 messages::internalError(asyncResp->res);
1806 return;
1807 }
1808 asyncResp->res.jsonValue["Locked"] = *userLocked;
1809 asyncResp->res
1810 .jsonValue["Locked@Redfish.AllowableValues"] = {
1811 "false"}; // can only unlock accounts
1812 }
1813 else if (property.first == "UserPrivilege")
1814 {
1815 const std::string* userPrivPtr =
1816 std::get_if<std::string>(&property.second);
1817 if (userPrivPtr == nullptr)
1818 {
1819 BMCWEB_LOG_ERROR << "UserPrivilege wasn't a "
1820 "string";
1821 messages::internalError(asyncResp->res);
1822 return;
1823 }
1824 std::string role = getRoleIdFromPrivilege(*userPrivPtr);
1825 if (role.empty())
1826 {
1827 BMCWEB_LOG_ERROR << "Invalid user role";
1828 messages::internalError(asyncResp->res);
1829 return;
1830 }
1831 asyncResp->res.jsonValue["RoleId"] = role;
1832
1833 nlohmann::json& roleEntry =
1834 asyncResp->res.jsonValue["Links"]["Role"];
1835 roleEntry["@odata.id"] =
1836 "/redfish/v1/AccountService/Roles/" + role;
1837 }
1838 else if (property.first == "UserPasswordExpired")
1839 {
1840 const bool* userPasswordExpired =
1841 std::get_if<bool>(&property.second);
1842 if (userPasswordExpired == nullptr)
1843 {
1844 BMCWEB_LOG_ERROR
1845 << "UserPasswordExpired wasn't a bool";
1846 messages::internalError(asyncResp->res);
1847 return;
1848 }
1849 asyncResp->res.jsonValue["PasswordChangeRequired"] =
1850 *userPasswordExpired;
1851 }
Abhishek Patelc7229812022-02-01 10:07:15 -06001852 else if (property.first == "UserGroups")
1853 {
1854 const std::vector<std::string>* userGroups =
1855 std::get_if<std::vector<std::string>>(
1856 &property.second);
1857 if (userGroups == nullptr)
1858 {
1859 BMCWEB_LOG_ERROR
1860 << "userGroups wasn't a string vector";
1861 messages::internalError(asyncResp->res);
1862 return;
1863 }
1864 if (!translateUserGroup(*userGroups, asyncResp->res))
1865 {
1866 BMCWEB_LOG_ERROR << "userGroups mapping failed";
1867 messages::internalError(asyncResp->res);
1868 return;
1869 }
1870 }
Ed Tanous1ef4c342022-05-12 16:12:36 -07001871 }
1872 }
1873 }
1874
1875 asyncResp->res.jsonValue["@odata.id"] =
1876 "/redfish/v1/AccountService/Accounts/" + accountName;
1877 asyncResp->res.jsonValue["Id"] = accountName;
1878 asyncResp->res.jsonValue["UserName"] = accountName;
1879 },
1880 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
1881 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
1882}
1883
1884inline void
1885 handleAccounttDelete(App& app, const crow::Request& req,
1886 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1887 const std::string& username)
1888{
1889 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1890 {
1891 return;
1892 }
1893
1894#ifdef BMCWEB_INSECURE_DISABLE_AUTHENTICATION
1895 // If authentication is disabled, there are no user accounts
Jiaqing Zhaod8a5d5d2022-08-05 16:21:51 +08001896 messages::resourceNotFound(asyncResp->res, "ManagerAccount", username);
Ed Tanous1ef4c342022-05-12 16:12:36 -07001897 return;
1898
1899#endif // BMCWEB_INSECURE_DISABLE_AUTHENTICATION
1900 sdbusplus::message::object_path tempObjPath(rootUserDbusPath);
1901 tempObjPath /= username;
1902 const std::string userPath(tempObjPath);
1903
1904 crow::connections::systemBus->async_method_call(
1905 [asyncResp, username](const boost::system::error_code ec) {
1906 if (ec)
1907 {
Jiaqing Zhaod8a5d5d2022-08-05 16:21:51 +08001908 messages::resourceNotFound(asyncResp->res, "ManagerAccount",
Ed Tanous1ef4c342022-05-12 16:12:36 -07001909 username);
1910 return;
1911 }
1912
1913 messages::accountRemoved(asyncResp->res);
1914 },
1915 "xyz.openbmc_project.User.Manager", userPath,
1916 "xyz.openbmc_project.Object.Delete", "Delete");
1917}
1918
1919inline void
1920 handleAccountPatch(App& app, const crow::Request& req,
1921 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1922 const std::string& username)
1923{
1924 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1925 {
1926 return;
1927 }
1928#ifdef BMCWEB_INSECURE_DISABLE_AUTHENTICATION
1929 // If authentication is disabled, there are no user accounts
Jiaqing Zhaod8a5d5d2022-08-05 16:21:51 +08001930 messages::resourceNotFound(asyncResp->res, "ManagerAccount", username);
Ed Tanous1ef4c342022-05-12 16:12:36 -07001931 return;
1932
1933#endif // BMCWEB_INSECURE_DISABLE_AUTHENTICATION
1934 std::optional<std::string> newUserName;
1935 std::optional<std::string> password;
1936 std::optional<bool> enabled;
1937 std::optional<std::string> roleId;
1938 std::optional<bool> locked;
1939
1940 if (req.session == nullptr)
1941 {
1942 messages::internalError(asyncResp->res);
1943 return;
1944 }
1945
1946 Privileges effectiveUserPrivileges =
1947 redfish::getUserPrivileges(req.userRole);
1948 Privileges configureUsers = {"ConfigureUsers"};
1949 bool userHasConfigureUsers =
1950 effectiveUserPrivileges.isSupersetOf(configureUsers);
1951 if (userHasConfigureUsers)
1952 {
1953 // Users with ConfigureUsers can modify for all users
1954 if (!json_util::readJsonPatch(req, asyncResp->res, "UserName",
1955 newUserName, "Password", password,
1956 "RoleId", roleId, "Enabled", enabled,
1957 "Locked", locked))
1958 {
1959 return;
1960 }
1961 }
1962 else
1963 {
1964 // ConfigureSelf accounts can only modify their own account
1965 if (username != req.session->username)
1966 {
1967 messages::insufficientPrivilege(asyncResp->res);
1968 return;
1969 }
1970
1971 // ConfigureSelf accounts can only modify their password
1972 if (!json_util::readJsonPatch(req, asyncResp->res, "Password",
1973 password))
1974 {
1975 return;
1976 }
1977 }
1978
1979 // if user name is not provided in the patch method or if it
1980 // matches the user name in the URI, then we are treating it as
1981 // updating user properties other then username. If username
1982 // provided doesn't match the URI, then we are treating this as
1983 // user rename request.
1984 if (!newUserName || (newUserName.value() == username))
1985 {
1986 updateUserProperties(asyncResp, username, password, enabled, roleId,
1987 locked);
1988 return;
1989 }
1990 crow::connections::systemBus->async_method_call(
1991 [asyncResp, username, password(std::move(password)),
1992 roleId(std::move(roleId)), enabled, newUser{std::string(*newUserName)},
Patrick Williams59d494e2022-07-22 19:26:55 -05001993 locked](const boost::system::error_code ec, sdbusplus::message_t& m) {
Ed Tanous1ef4c342022-05-12 16:12:36 -07001994 if (ec)
1995 {
1996 userErrorMessageHandler(m.get_error(), asyncResp, newUser,
1997 username);
1998 return;
1999 }
2000
2001 updateUserProperties(asyncResp, newUser, password, enabled, roleId,
2002 locked);
2003 },
2004 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
2005 "xyz.openbmc_project.User.Manager", "RenameUser", username,
2006 *newUserName);
2007}
2008
Ed Tanous6c51eab2021-06-03 12:30:29 -07002009inline void requestAccountServiceRoutes(App& app)
Ed Tanousb9b2e0b2018-09-13 13:47:50 -07002010{
Ed Tanousb9b2e0b2018-09-13 13:47:50 -07002011
Ed Tanous6c51eab2021-06-03 12:30:29 -07002012 BMCWEB_ROUTE(app, "/redfish/v1/AccountService/")
Ed Tanous4c7d4d32022-07-07 15:29:35 -07002013 .privileges(redfish::privileges::headAccountService)
2014 .methods(boost::beast::http::verb::head)(
2015 std::bind_front(handleAccountServiceHead, std::ref(app)));
2016
2017 BMCWEB_ROUTE(app, "/redfish/v1/AccountService/")
Ed Tanoused398212021-06-09 17:05:54 -07002018 .privileges(redfish::privileges::getAccountService)
Ed Tanous002d39b2022-05-31 08:59:27 -07002019 .methods(boost::beast::http::verb::get)(
Ed Tanous1ef4c342022-05-12 16:12:36 -07002020 std::bind_front(handleAccountServiceGet, std::ref(app)));
Ed Tanous6c51eab2021-06-03 12:30:29 -07002021
Ed Tanousf5ffd802021-07-19 10:55:33 -07002022 BMCWEB_ROUTE(app, "/redfish/v1/AccountService/")
Gunnar Mills1ec43ee2022-01-04 15:39:52 -06002023 .privileges(redfish::privileges::patchAccountService)
Ed Tanousf5ffd802021-07-19 10:55:33 -07002024 .methods(boost::beast::http::verb::patch)(
Ed Tanous1ef4c342022-05-12 16:12:36 -07002025 std::bind_front(handleAccountServicePatch, std::ref(app)));
Ed Tanousf5ffd802021-07-19 10:55:33 -07002026
Ed Tanous6c51eab2021-06-03 12:30:29 -07002027 BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/")
Ed Tanous4c7d4d32022-07-07 15:29:35 -07002028 .privileges(redfish::privileges::headManagerAccountCollection)
2029 .methods(boost::beast::http::verb::head)(
2030 std::bind_front(handleAccountCollectionHead, std::ref(app)));
2031
2032 BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/")
Ed Tanoused398212021-06-09 17:05:54 -07002033 .privileges(redfish::privileges::getManagerAccountCollection)
Ed Tanous6c51eab2021-06-03 12:30:29 -07002034 .methods(boost::beast::http::verb::get)(
Ed Tanous1ef4c342022-05-12 16:12:36 -07002035 std::bind_front(handleAccountCollectionGet, std::ref(app)));
Ed Tanous06e086d2018-09-19 17:19:52 -07002036
Ed Tanous6c51eab2021-06-03 12:30:29 -07002037 BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/")
Ed Tanoused398212021-06-09 17:05:54 -07002038 .privileges(redfish::privileges::postManagerAccountCollection)
Ed Tanous002d39b2022-05-31 08:59:27 -07002039 .methods(boost::beast::http::verb::post)(
Ed Tanous1ef4c342022-05-12 16:12:36 -07002040 std::bind_front(handleAccountCollectionPost, std::ref(app)));
Ed Tanous002d39b2022-05-31 08:59:27 -07002041
2042 BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/<str>/")
Ed Tanous4c7d4d32022-07-07 15:29:35 -07002043 .privileges(redfish::privileges::headManagerAccount)
2044 .methods(boost::beast::http::verb::head)(
2045 std::bind_front(handleAccountHead, std::ref(app)));
2046
2047 BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/<str>/")
Ed Tanous002d39b2022-05-31 08:59:27 -07002048 .privileges(redfish::privileges::getManagerAccount)
2049 .methods(boost::beast::http::verb::get)(
Ed Tanous1ef4c342022-05-12 16:12:36 -07002050 std::bind_front(handleAccountGet, 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 // TODO this privilege should be using the generated endpoints, but
2054 // because of the special handling of ConfigureSelf, it's not able to
2055 // yet
Ed Tanous6c51eab2021-06-03 12:30:29 -07002056 .privileges({{"ConfigureUsers"}, {"ConfigureSelf"}})
2057 .methods(boost::beast::http::verb::patch)(
Ed Tanous1ef4c342022-05-12 16:12:36 -07002058 std::bind_front(handleAccountPatch, std::ref(app)));
Ed Tanous6c51eab2021-06-03 12:30:29 -07002059
2060 BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002061 .privileges(redfish::privileges::deleteManagerAccount)
Ed Tanous6c51eab2021-06-03 12:30:29 -07002062 .methods(boost::beast::http::verb::delete_)(
Ed Tanous1ef4c342022-05-12 16:12:36 -07002063 std::bind_front(handleAccounttDelete, std::ref(app)));
Ed Tanous6c51eab2021-06-03 12:30:29 -07002064}
Lewanczyk, Dawid88d16c92018-02-02 14:51:09 +01002065
Ed Tanous1abe55e2018-09-05 08:30:59 -07002066} // namespace redfish