blob: b4c920557e10bf269517344aabb8dbb8130e9e3c [file] [log] [blame]
Lewanczyk, Dawid88d16c92018-02-02 14:51:09 +01001/*
2// Copyright (c) 2018 Intel Corporation
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15*/
16#pragma once
Lewanczyk, Dawid88d16c92018-02-02 14:51:09 +010017
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080018#include "app.hpp"
19#include "dbus_utility.hpp"
20#include "error_messages.hpp"
Ed Tanous0ec8b832022-03-14 14:56:47 -070021#include "generated/enums/account_service.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080022#include "openbmc_dbus_rest.hpp"
23#include "persistent_data.hpp"
24#include "query.hpp"
Ed Tanous0ec8b832022-03-14 14:56:47 -070025#include "registries/privilege_registry.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080026#include "utils/dbus_utils.hpp"
27#include "utils/json_utils.hpp"
Ed Tanous0ec8b832022-03-14 14:56:47 -070028
Jonathan Doman1e1e5982021-06-11 09:36:17 -070029#include <sdbusplus/asio/property.hpp>
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +020030#include <sdbusplus/unpack_properties.hpp>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050031
George Liu2b731192023-01-11 16:27:13 +080032#include <array>
Abhishek Patelc7229812022-02-01 10:07:15 -060033#include <optional>
34#include <string>
George Liu2b731192023-01-11 16:27:13 +080035#include <string_view>
Abhishek Patelc7229812022-02-01 10:07:15 -060036#include <vector>
37
Ed Tanous1abe55e2018-09-05 08:30:59 -070038namespace redfish
39{
Lewanczyk, Dawid88d16c92018-02-02 14:51:09 +010040
Ed Tanous23a21a12020-07-25 04:45:05 +000041constexpr const char* ldapConfigObjectName =
Ratan Gupta6973a582018-12-13 18:25:44 +053042 "/xyz/openbmc_project/user/ldap/openldap";
Ed Tanous2c70f802020-09-28 14:29:23 -070043constexpr const char* adConfigObject =
Ratan Guptaab828d72019-04-22 14:18:33 +053044 "/xyz/openbmc_project/user/ldap/active_directory";
45
P Dheeraj Srujan Kumarb477fd42021-12-16 07:17:51 +053046constexpr const char* rootUserDbusPath = "/xyz/openbmc_project/user/";
Ratan Gupta6973a582018-12-13 18:25:44 +053047constexpr const char* ldapRootObject = "/xyz/openbmc_project/user/ldap";
48constexpr const char* ldapDbusService = "xyz.openbmc_project.Ldap.Config";
49constexpr const char* ldapConfigInterface =
50 "xyz.openbmc_project.User.Ldap.Config";
51constexpr const char* ldapCreateInterface =
52 "xyz.openbmc_project.User.Ldap.Create";
53constexpr const char* ldapEnableInterface = "xyz.openbmc_project.Object.Enable";
Ratan Gupta06785242019-07-26 22:30:16 +053054constexpr const char* ldapPrivMapperInterface =
55 "xyz.openbmc_project.User.PrivilegeMapper";
Ratan Gupta6973a582018-12-13 18:25:44 +053056constexpr const char* dbusObjManagerIntf = "org.freedesktop.DBus.ObjectManager";
57constexpr const char* propertyInterface = "org.freedesktop.DBus.Properties";
Ratan Gupta6973a582018-12-13 18:25:44 +053058
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -060059struct LDAPRoleMapData
60{
61 std::string groupName;
62 std::string privilege;
63};
64
Ratan Gupta6973a582018-12-13 18:25:44 +053065struct LDAPConfigData
66{
67 std::string uri{};
68 std::string bindDN{};
69 std::string baseDN{};
70 std::string searchScope{};
71 std::string serverType{};
72 bool serviceEnabled = false;
73 std::string userNameAttribute{};
74 std::string groupAttribute{};
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -060075 std::vector<std::pair<std::string, LDAPRoleMapData>> groupRoleList;
Ratan Gupta6973a582018-12-13 18:25:44 +053076};
77
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -060078inline std::string getRoleIdFromPrivilege(std::string_view role)
AppaRao Puli84e12cb2018-10-11 01:28:15 +053079{
80 if (role == "priv-admin")
81 {
82 return "Administrator";
83 }
Ed Tanous3174e4d2020-10-07 11:41:22 -070084 if (role == "priv-user")
AppaRao Puli84e12cb2018-10-11 01:28:15 +053085 {
AppaRao Pulic80fee52019-10-16 14:49:36 +053086 return "ReadOnly";
AppaRao Puli84e12cb2018-10-11 01:28:15 +053087 }
Ed Tanous3174e4d2020-10-07 11:41:22 -070088 if (role == "priv-operator")
AppaRao Puli84e12cb2018-10-11 01:28:15 +053089 {
90 return "Operator";
91 }
92 return "";
93}
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -060094inline std::string getPrivilegeFromRoleId(std::string_view role)
AppaRao Puli84e12cb2018-10-11 01:28:15 +053095{
96 if (role == "Administrator")
97 {
98 return "priv-admin";
99 }
Ed Tanous3174e4d2020-10-07 11:41:22 -0700100 if (role == "ReadOnly")
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530101 {
102 return "priv-user";
103 }
Ed Tanous3174e4d2020-10-07 11:41:22 -0700104 if (role == "Operator")
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530105 {
106 return "priv-operator";
107 }
108 return "";
109}
Ed Tanousb9b2e0b2018-09-13 13:47:50 -0700110
Abhishek Patelc7229812022-02-01 10:07:15 -0600111/**
112 * @brief Maps user group names retrieved from D-Bus object to
113 * Account Types.
114 *
115 * @param[in] userGroups List of User groups
116 * @param[out] res AccountTypes populated
117 *
118 * @return true in case of success, false if UserGroups contains
119 * invalid group name(s).
120 */
121inline bool translateUserGroup(const std::vector<std::string>& userGroups,
122 crow::Response& res)
123{
124 std::vector<std::string> accountTypes;
125 for (const auto& userGroup : userGroups)
126 {
127 if (userGroup == "redfish")
128 {
129 accountTypes.emplace_back("Redfish");
130 accountTypes.emplace_back("WebUI");
131 }
132 else if (userGroup == "ipmi")
133 {
134 accountTypes.emplace_back("IPMI");
135 }
136 else if (userGroup == "ssh")
137 {
138 accountTypes.emplace_back("HostConsole");
139 accountTypes.emplace_back("ManagerConsole");
140 }
141 else if (userGroup == "web")
142 {
143 // 'web' is one of the valid groups in the UserGroups property of
144 // the user account in the D-Bus object. This group is currently not
145 // doing anything, and is considered to be equivalent to 'redfish'.
146 // 'redfish' user group is mapped to 'Redfish'and 'WebUI'
147 // AccountTypes, so do nothing here...
148 }
149 else
150 {
151 // Invalid user group name. Caller throws an excption.
152 return false;
153 }
154 }
155
156 res.jsonValue["AccountTypes"] = std::move(accountTypes);
157 return true;
158}
159
zhanghch058d1b46d2021-04-01 11:18:24 +0800160inline void userErrorMessageHandler(
161 const sd_bus_error* e, const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
162 const std::string& newUser, const std::string& username)
jayaprakash Mutyala66b5ca72019-08-07 20:26:37 +0000163{
jayaprakash Mutyala66b5ca72019-08-07 20:26:37 +0000164 if (e == nullptr)
165 {
166 messages::internalError(asyncResp->res);
167 return;
168 }
169
Manojkiran Eda055806b2020-11-03 09:36:28 +0530170 const char* errorMessage = e->name;
jayaprakash Mutyala66b5ca72019-08-07 20:26:37 +0000171 if (strcmp(errorMessage,
172 "xyz.openbmc_project.User.Common.Error.UserNameExists") == 0)
173 {
Jiaqing Zhaod8a5d5d2022-08-05 16:21:51 +0800174 messages::resourceAlreadyExists(asyncResp->res, "ManagerAccount",
jayaprakash Mutyala66b5ca72019-08-07 20:26:37 +0000175 "UserName", newUser);
176 }
177 else if (strcmp(errorMessage, "xyz.openbmc_project.User.Common.Error."
178 "UserNameDoesNotExist") == 0)
179 {
Jiaqing Zhaod8a5d5d2022-08-05 16:21:51 +0800180 messages::resourceNotFound(asyncResp->res, "ManagerAccount", username);
jayaprakash Mutyala66b5ca72019-08-07 20:26:37 +0000181 }
Ed Tanousd4d25792020-09-29 15:15:03 -0700182 else if ((strcmp(errorMessage,
183 "xyz.openbmc_project.Common.Error.InvalidArgument") ==
184 0) ||
George Liu0fda0f12021-11-16 10:06:17 +0800185 (strcmp(
186 errorMessage,
187 "xyz.openbmc_project.User.Common.Error.UserNameGroupFail") ==
188 0))
jayaprakash Mutyala66b5ca72019-08-07 20:26:37 +0000189 {
190 messages::propertyValueFormatError(asyncResp->res, newUser, "UserName");
191 }
192 else if (strcmp(errorMessage,
193 "xyz.openbmc_project.User.Common.Error.NoResource") == 0)
194 {
195 messages::createLimitReachedForResource(asyncResp->res);
196 }
jayaprakash Mutyala66b5ca72019-08-07 20:26:37 +0000197 else
198 {
199 messages::internalError(asyncResp->res);
200 }
jayaprakash Mutyala66b5ca72019-08-07 20:26:37 +0000201}
202
Ed Tanous81ce6092020-12-17 16:54:55 +0000203inline void parseLDAPConfigData(nlohmann::json& jsonResponse,
Ed Tanous23a21a12020-07-25 04:45:05 +0000204 const LDAPConfigData& confData,
205 const std::string& ldapType)
Ratan Gupta6973a582018-12-13 18:25:44 +0530206{
Patrick Williams89492a12023-05-10 07:51:34 -0500207 std::string service = (ldapType == "LDAP") ? "LDAPService"
208 : "ActiveDirectoryService";
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600209
Ed Tanous14766872022-03-15 10:44:42 -0700210 nlohmann::json& ldap = jsonResponse[ldapType];
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600211
Ed Tanous14766872022-03-15 10:44:42 -0700212 ldap["ServiceEnabled"] = confData.serviceEnabled;
213 ldap["ServiceAddresses"] = nlohmann::json::array({confData.uri});
Ed Tanous0ec8b832022-03-14 14:56:47 -0700214 ldap["Authentication"]["AuthenticationType"] =
215 account_service::AuthenticationTypes::UsernameAndPassword;
Ed Tanous14766872022-03-15 10:44:42 -0700216 ldap["Authentication"]["Username"] = confData.bindDN;
217 ldap["Authentication"]["Password"] = nullptr;
218
219 ldap["LDAPService"]["SearchSettings"]["BaseDistinguishedNames"] =
220 nlohmann::json::array({confData.baseDN});
221 ldap["LDAPService"]["SearchSettings"]["UsernameAttribute"] =
222 confData.userNameAttribute;
223 ldap["LDAPService"]["SearchSettings"]["GroupsAttribute"] =
224 confData.groupAttribute;
225
226 nlohmann::json& roleMapArray = ldap["RemoteRoleMapping"];
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600227 roleMapArray = nlohmann::json::array();
Ed Tanous9eb808c2022-01-25 10:19:23 -0800228 for (const auto& obj : confData.groupRoleList)
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600229 {
230 BMCWEB_LOG_DEBUG << "Pushing the data groupName="
231 << obj.second.groupName << "\n";
Ed Tanous613dabe2022-07-09 11:17:36 -0700232
Ed Tanous613dabe2022-07-09 11:17:36 -0700233 nlohmann::json::object_t remoteGroup;
234 remoteGroup["RemoteGroup"] = obj.second.groupName;
Jorge Cisneros329f0342022-11-04 16:26:25 +0000235 remoteGroup["LocalRole"] = getRoleIdFromPrivilege(obj.second.privilege);
236 roleMapArray.emplace_back(std::move(remoteGroup));
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600237 }
Ratan Gupta6973a582018-12-13 18:25:44 +0530238}
239
240/**
Ratan Gupta06785242019-07-26 22:30:16 +0530241 * @brief validates given JSON input and then calls appropriate method to
242 * create, to delete or to set Rolemapping object based on the given input.
243 *
244 */
Ed Tanous23a21a12020-07-25 04:45:05 +0000245inline void handleRoleMapPatch(
zhanghch058d1b46d2021-04-01 11:18:24 +0800246 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ratan Gupta06785242019-07-26 22:30:16 +0530247 const std::vector<std::pair<std::string, LDAPRoleMapData>>& roleMapObjData,
Ed Tanousf23b7292020-10-15 09:41:17 -0700248 const std::string& serverType, const std::vector<nlohmann::json>& input)
Ratan Gupta06785242019-07-26 22:30:16 +0530249{
250 for (size_t index = 0; index < input.size(); index++)
251 {
Ed Tanousf23b7292020-10-15 09:41:17 -0700252 const nlohmann::json& thisJson = input[index];
Ratan Gupta06785242019-07-26 22:30:16 +0530253
254 if (thisJson.is_null())
255 {
256 // delete the existing object
257 if (index < roleMapObjData.size())
258 {
259 crow::connections::systemBus->async_method_call(
260 [asyncResp, roleMapObjData, serverType,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800261 index](const boost::system::error_code& ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700262 if (ec)
263 {
264 BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
265 messages::internalError(asyncResp->res);
266 return;
267 }
Patrick Williams89492a12023-05-10 07:51:34 -0500268 asyncResp->res.jsonValue[serverType]["RemoteRoleMapping"]
269 [index] = nullptr;
Ratan Gupta06785242019-07-26 22:30:16 +0530270 },
271 ldapDbusService, roleMapObjData[index].first,
272 "xyz.openbmc_project.Object.Delete", "Delete");
273 }
274 else
275 {
276 BMCWEB_LOG_ERROR << "Can't delete the object";
277 messages::propertyValueTypeError(
Ed Tanous71f52d92021-02-19 08:51:17 -0800278 asyncResp->res,
279 thisJson.dump(2, ' ', true,
280 nlohmann::json::error_handler_t::replace),
Ratan Gupta06785242019-07-26 22:30:16 +0530281 "RemoteRoleMapping/" + std::to_string(index));
282 return;
283 }
284 }
285 else if (thisJson.empty())
286 {
287 // Don't do anything for the empty objects,parse next json
288 // eg {"RemoteRoleMapping",[{}]}
289 }
290 else
291 {
292 // update/create the object
293 std::optional<std::string> remoteGroup;
294 std::optional<std::string> localRole;
295
Ed Tanousf23b7292020-10-15 09:41:17 -0700296 // This is a copy, but it's required in this case because of how
297 // readJson is structured
298 nlohmann::json thisJsonCopy = thisJson;
299 if (!json_util::readJson(thisJsonCopy, asyncResp->res,
300 "RemoteGroup", remoteGroup, "LocalRole",
301 localRole))
Ratan Gupta06785242019-07-26 22:30:16 +0530302 {
303 continue;
304 }
305
306 // Update existing RoleMapping Object
307 if (index < roleMapObjData.size())
308 {
309 BMCWEB_LOG_DEBUG << "Update Role Map Object";
310 // If "RemoteGroup" info is provided
311 if (remoteGroup)
312 {
313 crow::connections::systemBus->async_method_call(
314 [asyncResp, roleMapObjData, serverType, index,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800315 remoteGroup](const boost::system::error_code& ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700316 if (ec)
317 {
318 BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
319 messages::internalError(asyncResp->res);
320 return;
321 }
322 asyncResp->res
323 .jsonValue[serverType]["RemoteRoleMapping"][index]
324 ["RemoteGroup"] = *remoteGroup;
Ratan Gupta06785242019-07-26 22:30:16 +0530325 },
326 ldapDbusService, roleMapObjData[index].first,
327 propertyInterface, "Set",
328 "xyz.openbmc_project.User.PrivilegeMapperEntry",
329 "GroupName",
Ed Tanous168e20c2021-12-13 14:39:53 -0800330 dbus::utility::DbusVariantType(
331 std::move(*remoteGroup)));
Ratan Gupta06785242019-07-26 22:30:16 +0530332 }
333
334 // If "LocalRole" info is provided
335 if (localRole)
336 {
337 crow::connections::systemBus->async_method_call(
338 [asyncResp, roleMapObjData, serverType, index,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800339 localRole](const boost::system::error_code& ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700340 if (ec)
341 {
342 BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
343 messages::internalError(asyncResp->res);
344 return;
345 }
346 asyncResp->res
347 .jsonValue[serverType]["RemoteRoleMapping"][index]
348 ["LocalRole"] = *localRole;
Ratan Gupta06785242019-07-26 22:30:16 +0530349 },
350 ldapDbusService, roleMapObjData[index].first,
351 propertyInterface, "Set",
352 "xyz.openbmc_project.User.PrivilegeMapperEntry",
353 "Privilege",
Ed Tanous168e20c2021-12-13 14:39:53 -0800354 dbus::utility::DbusVariantType(
Ratan Gupta06785242019-07-26 22:30:16 +0530355 getPrivilegeFromRoleId(std::move(*localRole))));
356 }
357 }
358 // Create a new RoleMapping Object.
359 else
360 {
361 BMCWEB_LOG_DEBUG
362 << "setRoleMappingProperties: Creating new Object";
Patrick Williams89492a12023-05-10 07:51:34 -0500363 std::string pathString = "RemoteRoleMapping/" +
364 std::to_string(index);
Ratan Gupta06785242019-07-26 22:30:16 +0530365
366 if (!localRole)
367 {
368 messages::propertyMissing(asyncResp->res,
369 pathString + "/LocalRole");
370 continue;
371 }
372 if (!remoteGroup)
373 {
374 messages::propertyMissing(asyncResp->res,
375 pathString + "/RemoteGroup");
376 continue;
377 }
378
379 std::string dbusObjectPath;
380 if (serverType == "ActiveDirectory")
381 {
Ed Tanous2c70f802020-09-28 14:29:23 -0700382 dbusObjectPath = adConfigObject;
Ratan Gupta06785242019-07-26 22:30:16 +0530383 }
384 else if (serverType == "LDAP")
385 {
Ed Tanous23a21a12020-07-25 04:45:05 +0000386 dbusObjectPath = ldapConfigObjectName;
Ratan Gupta06785242019-07-26 22:30:16 +0530387 }
388
389 BMCWEB_LOG_DEBUG << "Remote Group=" << *remoteGroup
390 << ",LocalRole=" << *localRole;
391
392 crow::connections::systemBus->async_method_call(
Ed Tanous271584a2019-07-09 16:24:22 -0700393 [asyncResp, serverType, localRole,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800394 remoteGroup](const boost::system::error_code& ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700395 if (ec)
396 {
397 BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
398 messages::internalError(asyncResp->res);
399 return;
400 }
401 nlohmann::json& remoteRoleJson =
402 asyncResp->res
403 .jsonValue[serverType]["RemoteRoleMapping"];
404 nlohmann::json::object_t roleMapEntry;
405 roleMapEntry["LocalRole"] = *localRole;
406 roleMapEntry["RemoteGroup"] = *remoteGroup;
Patrick Williamsb2ba3072023-05-12 10:27:39 -0500407 remoteRoleJson.emplace_back(std::move(roleMapEntry));
Ratan Gupta06785242019-07-26 22:30:16 +0530408 },
409 ldapDbusService, dbusObjectPath, ldapPrivMapperInterface,
Ed Tanous3174e4d2020-10-07 11:41:22 -0700410 "Create", *remoteGroup,
Ratan Gupta06785242019-07-26 22:30:16 +0530411 getPrivilegeFromRoleId(std::move(*localRole)));
412 }
413 }
414 }
415}
416
417/**
Ratan Gupta6973a582018-12-13 18:25:44 +0530418 * Function that retrieves all properties for LDAP config object
419 * into JSON
420 */
421template <typename CallbackFunc>
422inline void getLDAPConfigData(const std::string& ldapType,
423 CallbackFunc&& callback)
424{
George Liu2b731192023-01-11 16:27:13 +0800425 constexpr std::array<std::string_view, 2> interfaces = {
426 ldapEnableInterface, ldapConfigInterface};
Ratan Gupta6973a582018-12-13 18:25:44 +0530427
George Liu2b731192023-01-11 16:27:13 +0800428 dbus::utility::getDbusObject(
429 ldapConfigObjectName, interfaces,
430 [callback, ldapType](const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800431 const dbus::utility::MapperGetObject& resp) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700432 if (ec || resp.empty())
433 {
434 BMCWEB_LOG_ERROR
435 << "DBUS response error during getting of service name: " << ec;
436 LDAPConfigData empty{};
437 callback(false, empty, ldapType);
438 return;
439 }
440 std::string service = resp.begin()->first;
441 crow::connections::systemBus->async_method_call(
442 [callback,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800443 ldapType](const boost::system::error_code& errorCode,
Ed Tanous002d39b2022-05-31 08:59:27 -0700444 const dbus::utility::ManagedObjectType& ldapObjects) {
445 LDAPConfigData confData{};
446 if (errorCode)
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600447 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700448 callback(false, confData, ldapType);
449 BMCWEB_LOG_ERROR << "D-Bus responses error: " << errorCode;
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600450 return;
451 }
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600452
Ed Tanous002d39b2022-05-31 08:59:27 -0700453 std::string ldapDbusType;
454 std::string searchString;
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600455
Ed Tanous002d39b2022-05-31 08:59:27 -0700456 if (ldapType == "LDAP")
457 {
458 ldapDbusType =
459 "xyz.openbmc_project.User.Ldap.Config.Type.OpenLdap";
460 searchString = "openldap";
461 }
462 else if (ldapType == "ActiveDirectory")
463 {
464 ldapDbusType =
465 "xyz.openbmc_project.User.Ldap.Config.Type.ActiveDirectory";
466 searchString = "active_directory";
467 }
468 else
469 {
470 BMCWEB_LOG_ERROR << "Can't get the DbusType for the given type="
471 << ldapType;
472 callback(false, confData, ldapType);
473 return;
474 }
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600475
Ed Tanous002d39b2022-05-31 08:59:27 -0700476 std::string ldapEnableInterfaceStr = ldapEnableInterface;
477 std::string ldapConfigInterfaceStr = ldapConfigInterface;
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600478
Ed Tanous002d39b2022-05-31 08:59:27 -0700479 for (const auto& object : ldapObjects)
480 {
481 // let's find the object whose ldap type is equal to the
482 // given type
483 if (object.first.str.find(searchString) == std::string::npos)
484 {
485 continue;
486 }
487
488 for (const auto& interface : object.second)
489 {
490 if (interface.first == ldapEnableInterfaceStr)
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600491 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700492 // rest of the properties are string.
493 for (const auto& property : interface.second)
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600494 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700495 if (property.first == "Enabled")
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600496 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700497 const bool* value =
498 std::get_if<bool>(&property.second);
499 if (value == nullptr)
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600500 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700501 continue;
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600502 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700503 confData.serviceEnabled = *value;
504 break;
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600505 }
506 }
507 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700508 else if (interface.first == ldapConfigInterfaceStr)
509 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700510 for (const auto& property : interface.second)
511 {
512 const std::string* strValue =
513 std::get_if<std::string>(&property.second);
514 if (strValue == nullptr)
515 {
516 continue;
517 }
518 if (property.first == "LDAPServerURI")
519 {
520 confData.uri = *strValue;
521 }
522 else if (property.first == "LDAPBindDN")
523 {
524 confData.bindDN = *strValue;
525 }
526 else if (property.first == "LDAPBaseDN")
527 {
528 confData.baseDN = *strValue;
529 }
530 else if (property.first == "LDAPSearchScope")
531 {
532 confData.searchScope = *strValue;
533 }
534 else if (property.first == "GroupNameAttribute")
535 {
536 confData.groupAttribute = *strValue;
537 }
538 else if (property.first == "UserNameAttribute")
539 {
540 confData.userNameAttribute = *strValue;
541 }
542 else if (property.first == "LDAPType")
543 {
544 confData.serverType = *strValue;
545 }
546 }
547 }
548 else if (interface.first ==
549 "xyz.openbmc_project.User.PrivilegeMapperEntry")
550 {
551 LDAPRoleMapData roleMapData{};
552 for (const auto& property : interface.second)
553 {
554 const std::string* strValue =
555 std::get_if<std::string>(&property.second);
556
557 if (strValue == nullptr)
558 {
559 continue;
560 }
561
562 if (property.first == "GroupName")
563 {
564 roleMapData.groupName = *strValue;
565 }
566 else if (property.first == "Privilege")
567 {
568 roleMapData.privilege = *strValue;
569 }
570 }
571
572 confData.groupRoleList.emplace_back(object.first.str,
573 roleMapData);
574 }
575 }
576 }
577 callback(true, confData, ldapType);
578 },
579 service, ldapRootObject, dbusObjManagerIntf, "GetManagedObjects");
George Liu2b731192023-01-11 16:27:13 +0800580 });
Ratan Gupta6973a582018-12-13 18:25:44 +0530581}
582
Ed Tanous6c51eab2021-06-03 12:30:29 -0700583/**
584 * @brief parses the authentication section under the LDAP
585 * @param input JSON data
586 * @param asyncResp pointer to the JSON response
587 * @param userName userName to be filled from the given JSON.
588 * @param password password to be filled from the given JSON.
589 */
Ed Tanous4f48d5f2021-06-21 08:27:45 -0700590inline void parseLDAPAuthenticationJson(
Ed Tanous6c51eab2021-06-03 12:30:29 -0700591 nlohmann::json input, const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
592 std::optional<std::string>& username, std::optional<std::string>& password)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700593{
Ed Tanous6c51eab2021-06-03 12:30:29 -0700594 std::optional<std::string> authType;
595
596 if (!json_util::readJson(input, asyncResp->res, "AuthenticationType",
597 authType, "Username", username, "Password",
598 password))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700599 {
Ed Tanous6c51eab2021-06-03 12:30:29 -0700600 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700601 }
Ed Tanous6c51eab2021-06-03 12:30:29 -0700602 if (!authType)
Ratan Gupta8a07d282019-03-16 08:33:47 +0530603 {
Ed Tanous6c51eab2021-06-03 12:30:29 -0700604 return;
Ratan Gupta8a07d282019-03-16 08:33:47 +0530605 }
Ed Tanous6c51eab2021-06-03 12:30:29 -0700606 if (*authType != "UsernameAndPassword")
Ratan Gupta8a07d282019-03-16 08:33:47 +0530607 {
Ed Tanous6c51eab2021-06-03 12:30:29 -0700608 messages::propertyValueNotInList(asyncResp->res, *authType,
609 "AuthenticationType");
610 return;
Ratan Gupta8a07d282019-03-16 08:33:47 +0530611 }
Ed Tanous6c51eab2021-06-03 12:30:29 -0700612}
613/**
614 * @brief parses the LDAPService section under the LDAP
615 * @param input JSON data
616 * @param asyncResp pointer to the JSON response
617 * @param baseDNList baseDN to be filled from the given JSON.
618 * @param userNameAttribute userName to be filled from the given JSON.
619 * @param groupaAttribute password to be filled from the given JSON.
620 */
Ratan Gupta8a07d282019-03-16 08:33:47 +0530621
Ed Tanous4f48d5f2021-06-21 08:27:45 -0700622inline void
623 parseLDAPServiceJson(nlohmann::json input,
624 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
625 std::optional<std::vector<std::string>>& baseDNList,
626 std::optional<std::string>& userNameAttribute,
627 std::optional<std::string>& groupsAttribute)
Ed Tanous6c51eab2021-06-03 12:30:29 -0700628{
629 std::optional<nlohmann::json> searchSettings;
630
631 if (!json_util::readJson(input, asyncResp->res, "SearchSettings",
632 searchSettings))
Ratan Gupta8a07d282019-03-16 08:33:47 +0530633 {
Ed Tanous6c51eab2021-06-03 12:30:29 -0700634 return;
Ratan Gupta8a07d282019-03-16 08:33:47 +0530635 }
Ed Tanous6c51eab2021-06-03 12:30:29 -0700636 if (!searchSettings)
Ratan Gupta8a07d282019-03-16 08:33:47 +0530637 {
Ed Tanous6c51eab2021-06-03 12:30:29 -0700638 return;
Ratan Gupta8a07d282019-03-16 08:33:47 +0530639 }
Ed Tanous6c51eab2021-06-03 12:30:29 -0700640 if (!json_util::readJson(*searchSettings, asyncResp->res,
641 "BaseDistinguishedNames", baseDNList,
642 "UsernameAttribute", userNameAttribute,
643 "GroupsAttribute", groupsAttribute))
Ratan Gupta8a07d282019-03-16 08:33:47 +0530644 {
Ed Tanous6c51eab2021-06-03 12:30:29 -0700645 return;
Ratan Gupta8a07d282019-03-16 08:33:47 +0530646 }
Ed Tanous6c51eab2021-06-03 12:30:29 -0700647}
648/**
649 * @brief updates the LDAP server address and updates the
650 json response with the new value.
651 * @param serviceAddressList address to be updated.
652 * @param asyncResp pointer to the JSON response
653 * @param ldapServerElementName Type of LDAP
654 server(openLDAP/ActiveDirectory)
655 */
Ratan Gupta8a07d282019-03-16 08:33:47 +0530656
Ed Tanous4f48d5f2021-06-21 08:27:45 -0700657inline void handleServiceAddressPatch(
Ed Tanous6c51eab2021-06-03 12:30:29 -0700658 const std::vector<std::string>& serviceAddressList,
659 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
660 const std::string& ldapServerElementName,
661 const std::string& ldapConfigObject)
662{
663 crow::connections::systemBus->async_method_call(
664 [asyncResp, ldapServerElementName,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800665 serviceAddressList](const boost::system::error_code& ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700666 if (ec)
667 {
668 BMCWEB_LOG_DEBUG
669 << "Error Occurred in updating the service address";
670 messages::internalError(asyncResp->res);
671 return;
672 }
673 std::vector<std::string> modifiedserviceAddressList = {
674 serviceAddressList.front()};
675 asyncResp->res.jsonValue[ldapServerElementName]["ServiceAddresses"] =
676 modifiedserviceAddressList;
677 if ((serviceAddressList).size() > 1)
678 {
679 messages::propertyValueModified(asyncResp->res, "ServiceAddresses",
680 serviceAddressList.front());
681 }
682 BMCWEB_LOG_DEBUG << "Updated the service address";
Ed Tanous6c51eab2021-06-03 12:30:29 -0700683 },
684 ldapDbusService, ldapConfigObject, propertyInterface, "Set",
685 ldapConfigInterface, "LDAPServerURI",
Ed Tanous168e20c2021-12-13 14:39:53 -0800686 dbus::utility::DbusVariantType(serviceAddressList.front()));
Ed Tanous6c51eab2021-06-03 12:30:29 -0700687}
688/**
689 * @brief updates the LDAP Bind DN and updates the
690 json response with the new value.
691 * @param username name of the user which needs to be updated.
692 * @param asyncResp pointer to the JSON response
693 * @param ldapServerElementName Type of LDAP
694 server(openLDAP/ActiveDirectory)
695 */
Ratan Gupta8a07d282019-03-16 08:33:47 +0530696
Ed Tanous4f48d5f2021-06-21 08:27:45 -0700697inline void
698 handleUserNamePatch(const std::string& username,
699 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
700 const std::string& ldapServerElementName,
701 const std::string& ldapConfigObject)
Ed Tanous6c51eab2021-06-03 12:30:29 -0700702{
703 crow::connections::systemBus->async_method_call(
704 [asyncResp, username,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800705 ldapServerElementName](const boost::system::error_code& ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700706 if (ec)
707 {
708 BMCWEB_LOG_DEBUG << "Error occurred in updating the username";
709 messages::internalError(asyncResp->res);
710 return;
711 }
Patrick Williams89492a12023-05-10 07:51:34 -0500712 asyncResp->res.jsonValue[ldapServerElementName]["Authentication"]
713 ["Username"] = username;
Ed Tanous002d39b2022-05-31 08:59:27 -0700714 BMCWEB_LOG_DEBUG << "Updated the username";
Ed Tanous6c51eab2021-06-03 12:30:29 -0700715 },
716 ldapDbusService, ldapConfigObject, propertyInterface, "Set",
Ed Tanous168e20c2021-12-13 14:39:53 -0800717 ldapConfigInterface, "LDAPBindDN",
718 dbus::utility::DbusVariantType(username));
Ed Tanous6c51eab2021-06-03 12:30:29 -0700719}
720
721/**
722 * @brief updates the LDAP password
723 * @param password : ldap password which needs to be updated.
724 * @param asyncResp pointer to the JSON response
725 * @param ldapServerElementName Type of LDAP
726 * server(openLDAP/ActiveDirectory)
727 */
728
Ed Tanous4f48d5f2021-06-21 08:27:45 -0700729inline void
730 handlePasswordPatch(const std::string& password,
731 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
732 const std::string& ldapServerElementName,
733 const std::string& ldapConfigObject)
Ed Tanous6c51eab2021-06-03 12:30:29 -0700734{
735 crow::connections::systemBus->async_method_call(
736 [asyncResp, password,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800737 ldapServerElementName](const boost::system::error_code& ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700738 if (ec)
739 {
740 BMCWEB_LOG_DEBUG << "Error occurred in updating the password";
741 messages::internalError(asyncResp->res);
742 return;
743 }
Patrick Williams89492a12023-05-10 07:51:34 -0500744 asyncResp->res.jsonValue[ldapServerElementName]["Authentication"]
745 ["Password"] = "";
Ed Tanous002d39b2022-05-31 08:59:27 -0700746 BMCWEB_LOG_DEBUG << "Updated the password";
Ed Tanous6c51eab2021-06-03 12:30:29 -0700747 },
748 ldapDbusService, ldapConfigObject, propertyInterface, "Set",
749 ldapConfigInterface, "LDAPBindDNPassword",
Ed Tanous168e20c2021-12-13 14:39:53 -0800750 dbus::utility::DbusVariantType(password));
Ed Tanous6c51eab2021-06-03 12:30:29 -0700751}
752
753/**
754 * @brief updates the LDAP BaseDN and updates the
755 json response with the new value.
756 * @param baseDNList baseDN list which needs to be updated.
757 * @param asyncResp pointer to the JSON response
758 * @param ldapServerElementName Type of LDAP
759 server(openLDAP/ActiveDirectory)
760 */
761
Ed Tanous4f48d5f2021-06-21 08:27:45 -0700762inline void
763 handleBaseDNPatch(const std::vector<std::string>& baseDNList,
764 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
765 const std::string& ldapServerElementName,
766 const std::string& ldapConfigObject)
Ed Tanous6c51eab2021-06-03 12:30:29 -0700767{
768 crow::connections::systemBus->async_method_call(
769 [asyncResp, baseDNList,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800770 ldapServerElementName](const boost::system::error_code& ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700771 if (ec)
772 {
773 BMCWEB_LOG_DEBUG << "Error Occurred in Updating the base DN";
774 messages::internalError(asyncResp->res);
775 return;
776 }
777 auto& serverTypeJson = asyncResp->res.jsonValue[ldapServerElementName];
778 auto& searchSettingsJson =
779 serverTypeJson["LDAPService"]["SearchSettings"];
780 std::vector<std::string> modifiedBaseDNList = {baseDNList.front()};
781 searchSettingsJson["BaseDistinguishedNames"] = modifiedBaseDNList;
782 if (baseDNList.size() > 1)
783 {
784 messages::propertyValueModified(
785 asyncResp->res, "BaseDistinguishedNames", baseDNList.front());
786 }
787 BMCWEB_LOG_DEBUG << "Updated the base DN";
Ed Tanous6c51eab2021-06-03 12:30:29 -0700788 },
789 ldapDbusService, ldapConfigObject, propertyInterface, "Set",
790 ldapConfigInterface, "LDAPBaseDN",
Ed Tanous168e20c2021-12-13 14:39:53 -0800791 dbus::utility::DbusVariantType(baseDNList.front()));
Ed Tanous6c51eab2021-06-03 12:30:29 -0700792}
793/**
794 * @brief updates the LDAP user name attribute and updates the
795 json response with the new value.
796 * @param userNameAttribute attribute to be updated.
797 * @param asyncResp pointer to the JSON response
798 * @param ldapServerElementName Type of LDAP
799 server(openLDAP/ActiveDirectory)
800 */
801
Ed Tanous4f48d5f2021-06-21 08:27:45 -0700802inline void
803 handleUserNameAttrPatch(const std::string& userNameAttribute,
804 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
805 const std::string& ldapServerElementName,
806 const std::string& ldapConfigObject)
Ed Tanous6c51eab2021-06-03 12:30:29 -0700807{
808 crow::connections::systemBus->async_method_call(
809 [asyncResp, userNameAttribute,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800810 ldapServerElementName](const boost::system::error_code& ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700811 if (ec)
812 {
813 BMCWEB_LOG_DEBUG << "Error Occurred in Updating the "
814 "username attribute";
815 messages::internalError(asyncResp->res);
816 return;
817 }
818 auto& serverTypeJson = asyncResp->res.jsonValue[ldapServerElementName];
819 auto& searchSettingsJson =
820 serverTypeJson["LDAPService"]["SearchSettings"];
821 searchSettingsJson["UsernameAttribute"] = userNameAttribute;
822 BMCWEB_LOG_DEBUG << "Updated the user name attr.";
Ed Tanous6c51eab2021-06-03 12:30:29 -0700823 },
824 ldapDbusService, ldapConfigObject, propertyInterface, "Set",
825 ldapConfigInterface, "UserNameAttribute",
Ed Tanous168e20c2021-12-13 14:39:53 -0800826 dbus::utility::DbusVariantType(userNameAttribute));
Ed Tanous6c51eab2021-06-03 12:30:29 -0700827}
828/**
829 * @brief updates the LDAP group attribute and updates the
830 json response with the new value.
831 * @param groupsAttribute attribute to be updated.
832 * @param asyncResp pointer to the JSON response
833 * @param ldapServerElementName Type of LDAP
834 server(openLDAP/ActiveDirectory)
835 */
836
Ed Tanous4f48d5f2021-06-21 08:27:45 -0700837inline void handleGroupNameAttrPatch(
Ed Tanous6c51eab2021-06-03 12:30:29 -0700838 const std::string& groupsAttribute,
839 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
840 const std::string& ldapServerElementName,
841 const std::string& ldapConfigObject)
842{
843 crow::connections::systemBus->async_method_call(
844 [asyncResp, groupsAttribute,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800845 ldapServerElementName](const boost::system::error_code& ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700846 if (ec)
847 {
848 BMCWEB_LOG_DEBUG << "Error Occurred in Updating the "
849 "groupname attribute";
850 messages::internalError(asyncResp->res);
851 return;
852 }
853 auto& serverTypeJson = asyncResp->res.jsonValue[ldapServerElementName];
854 auto& searchSettingsJson =
855 serverTypeJson["LDAPService"]["SearchSettings"];
856 searchSettingsJson["GroupsAttribute"] = groupsAttribute;
857 BMCWEB_LOG_DEBUG << "Updated the groupname attr";
Ed Tanous6c51eab2021-06-03 12:30:29 -0700858 },
859 ldapDbusService, ldapConfigObject, propertyInterface, "Set",
860 ldapConfigInterface, "GroupNameAttribute",
Ed Tanous168e20c2021-12-13 14:39:53 -0800861 dbus::utility::DbusVariantType(groupsAttribute));
Ed Tanous6c51eab2021-06-03 12:30:29 -0700862}
863/**
864 * @brief updates the LDAP service enable and updates the
865 json response with the new value.
866 * @param input JSON data.
867 * @param asyncResp pointer to the JSON response
868 * @param ldapServerElementName Type of LDAP
869 server(openLDAP/ActiveDirectory)
870 */
871
Ed Tanous4f48d5f2021-06-21 08:27:45 -0700872inline void handleServiceEnablePatch(
Ed Tanous6c51eab2021-06-03 12:30:29 -0700873 bool serviceEnabled, const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
874 const std::string& ldapServerElementName,
875 const std::string& ldapConfigObject)
876{
877 crow::connections::systemBus->async_method_call(
878 [asyncResp, serviceEnabled,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800879 ldapServerElementName](const boost::system::error_code& ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700880 if (ec)
881 {
882 BMCWEB_LOG_DEBUG << "Error Occurred in Updating the service enable";
883 messages::internalError(asyncResp->res);
884 return;
885 }
886 asyncResp->res.jsonValue[ldapServerElementName]["ServiceEnabled"] =
887 serviceEnabled;
888 BMCWEB_LOG_DEBUG << "Updated Service enable = " << serviceEnabled;
Ed Tanous6c51eab2021-06-03 12:30:29 -0700889 },
890 ldapDbusService, ldapConfigObject, propertyInterface, "Set",
Ed Tanous168e20c2021-12-13 14:39:53 -0800891 ldapEnableInterface, "Enabled",
892 dbus::utility::DbusVariantType(serviceEnabled));
Ed Tanous6c51eab2021-06-03 12:30:29 -0700893}
894
Ed Tanous4f48d5f2021-06-21 08:27:45 -0700895inline void
896 handleAuthMethodsPatch(nlohmann::json& input,
897 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Ed Tanous6c51eab2021-06-03 12:30:29 -0700898{
899 std::optional<bool> basicAuth;
900 std::optional<bool> cookie;
901 std::optional<bool> sessionToken;
902 std::optional<bool> xToken;
903 std::optional<bool> tls;
904
905 if (!json_util::readJson(input, asyncResp->res, "BasicAuth", basicAuth,
906 "Cookie", cookie, "SessionToken", sessionToken,
907 "XToken", xToken, "TLS", tls))
Ratan Gupta8a07d282019-03-16 08:33:47 +0530908 {
Ed Tanous6c51eab2021-06-03 12:30:29 -0700909 BMCWEB_LOG_ERROR << "Cannot read values from AuthMethod tag";
910 return;
911 }
912
913 // Make a copy of methods configuration
914 persistent_data::AuthConfigMethods authMethodsConfig =
915 persistent_data::SessionStore::getInstance().getAuthMethodsConfig();
916
917 if (basicAuth)
918 {
919#ifndef BMCWEB_ENABLE_BASIC_AUTHENTICATION
920 messages::actionNotSupported(
George Liu0fda0f12021-11-16 10:06:17 +0800921 asyncResp->res,
922 "Setting BasicAuth when basic-auth feature is disabled");
Ed Tanous6c51eab2021-06-03 12:30:29 -0700923 return;
924#endif
925 authMethodsConfig.basic = *basicAuth;
926 }
927
928 if (cookie)
929 {
930#ifndef BMCWEB_ENABLE_COOKIE_AUTHENTICATION
George Liu0fda0f12021-11-16 10:06:17 +0800931 messages::actionNotSupported(
932 asyncResp->res,
933 "Setting Cookie when cookie-auth feature is disabled");
Ed Tanous6c51eab2021-06-03 12:30:29 -0700934 return;
935#endif
936 authMethodsConfig.cookie = *cookie;
937 }
938
939 if (sessionToken)
940 {
941#ifndef BMCWEB_ENABLE_SESSION_AUTHENTICATION
942 messages::actionNotSupported(
George Liu0fda0f12021-11-16 10:06:17 +0800943 asyncResp->res,
944 "Setting SessionToken when session-auth feature is disabled");
Ed Tanous6c51eab2021-06-03 12:30:29 -0700945 return;
946#endif
947 authMethodsConfig.sessionToken = *sessionToken;
948 }
949
950 if (xToken)
951 {
952#ifndef BMCWEB_ENABLE_XTOKEN_AUTHENTICATION
George Liu0fda0f12021-11-16 10:06:17 +0800953 messages::actionNotSupported(
954 asyncResp->res,
955 "Setting XToken when xtoken-auth feature is disabled");
Ed Tanous6c51eab2021-06-03 12:30:29 -0700956 return;
957#endif
958 authMethodsConfig.xtoken = *xToken;
959 }
960
961 if (tls)
962 {
963#ifndef BMCWEB_ENABLE_MUTUAL_TLS_AUTHENTICATION
George Liu0fda0f12021-11-16 10:06:17 +0800964 messages::actionNotSupported(
965 asyncResp->res,
966 "Setting TLS when mutual-tls-auth feature is disabled");
Ed Tanous6c51eab2021-06-03 12:30:29 -0700967 return;
968#endif
969 authMethodsConfig.tls = *tls;
970 }
971
972 if (!authMethodsConfig.basic && !authMethodsConfig.cookie &&
973 !authMethodsConfig.sessionToken && !authMethodsConfig.xtoken &&
974 !authMethodsConfig.tls)
975 {
976 // Do not allow user to disable everything
977 messages::actionNotSupported(asyncResp->res,
978 "of disabling all available methods");
979 return;
980 }
981
982 persistent_data::SessionStore::getInstance().updateAuthMethodsConfig(
983 authMethodsConfig);
984 // Save configuration immediately
985 persistent_data::getConfig().writeData();
986
987 messages::success(asyncResp->res);
988}
989
990/**
991 * @brief Get the required values from the given JSON, validates the
992 * value and create the LDAP config object.
993 * @param input JSON data
994 * @param asyncResp pointer to the JSON response
995 * @param serverType Type of LDAP server(openLDAP/ActiveDirectory)
996 */
997
998inline void handleLDAPPatch(nlohmann::json& input,
999 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1000 const std::string& serverType)
1001{
1002 std::string dbusObjectPath;
1003 if (serverType == "ActiveDirectory")
1004 {
1005 dbusObjectPath = adConfigObject;
1006 }
1007 else if (serverType == "LDAP")
1008 {
1009 dbusObjectPath = ldapConfigObjectName;
1010 }
1011 else
1012 {
1013 return;
1014 }
1015
1016 std::optional<nlohmann::json> authentication;
1017 std::optional<nlohmann::json> ldapService;
1018 std::optional<std::vector<std::string>> serviceAddressList;
1019 std::optional<bool> serviceEnabled;
1020 std::optional<std::vector<std::string>> baseDNList;
1021 std::optional<std::string> userNameAttribute;
1022 std::optional<std::string> groupsAttribute;
1023 std::optional<std::string> userName;
1024 std::optional<std::string> password;
1025 std::optional<std::vector<nlohmann::json>> remoteRoleMapData;
1026
1027 if (!json_util::readJson(input, asyncResp->res, "Authentication",
1028 authentication, "LDAPService", ldapService,
1029 "ServiceAddresses", serviceAddressList,
1030 "ServiceEnabled", serviceEnabled,
1031 "RemoteRoleMapping", remoteRoleMapData))
1032 {
1033 return;
1034 }
1035
1036 if (authentication)
1037 {
1038 parseLDAPAuthenticationJson(*authentication, asyncResp, userName,
1039 password);
1040 }
1041 if (ldapService)
1042 {
1043 parseLDAPServiceJson(*ldapService, asyncResp, baseDNList,
1044 userNameAttribute, groupsAttribute);
1045 }
1046 if (serviceAddressList)
1047 {
Ed Tanous26f69762022-01-25 09:49:11 -08001048 if (serviceAddressList->empty())
Ratan Guptaeb2bbe52019-04-22 14:27:01 +05301049 {
Ed Tanous6c51eab2021-06-03 12:30:29 -07001050 messages::propertyValueNotInList(asyncResp->res, "[]",
1051 "ServiceAddress");
Ed Tanouscb13a392020-07-25 19:02:03 +00001052 return;
1053 }
Ed Tanous6c51eab2021-06-03 12:30:29 -07001054 }
1055 if (baseDNList)
1056 {
Ed Tanous26f69762022-01-25 09:49:11 -08001057 if (baseDNList->empty())
Ratan Gupta8a07d282019-03-16 08:33:47 +05301058 {
Ed Tanous6c51eab2021-06-03 12:30:29 -07001059 messages::propertyValueNotInList(asyncResp->res, "[]",
1060 "BaseDistinguishedNames");
Ratan Gupta8a07d282019-03-16 08:33:47 +05301061 return;
1062 }
Ed Tanous6c51eab2021-06-03 12:30:29 -07001063 }
Ratan Gupta8a07d282019-03-16 08:33:47 +05301064
Ed Tanous6c51eab2021-06-03 12:30:29 -07001065 // nothing to update, then return
1066 if (!userName && !password && !serviceAddressList && !baseDNList &&
1067 !userNameAttribute && !groupsAttribute && !serviceEnabled &&
1068 !remoteRoleMapData)
1069 {
1070 return;
1071 }
1072
1073 // Get the existing resource first then keep modifying
1074 // whenever any property gets updated.
Ed Tanous002d39b2022-05-31 08:59:27 -07001075 getLDAPConfigData(
1076 serverType,
1077 [asyncResp, userName, password, baseDNList, userNameAttribute,
1078 groupsAttribute, serviceAddressList, serviceEnabled, dbusObjectPath,
1079 remoteRoleMapData](bool success, const LDAPConfigData& confData,
1080 const std::string& serverT) {
Ed Tanous6c51eab2021-06-03 12:30:29 -07001081 if (!success)
Ratan Gupta8a07d282019-03-16 08:33:47 +05301082 {
Ed Tanous6c51eab2021-06-03 12:30:29 -07001083 messages::internalError(asyncResp->res);
1084 return;
Ratan Gupta8a07d282019-03-16 08:33:47 +05301085 }
Ed Tanous6c51eab2021-06-03 12:30:29 -07001086 parseLDAPConfigData(asyncResp->res.jsonValue, confData, serverT);
1087 if (confData.serviceEnabled)
Ratan Gupta8a07d282019-03-16 08:33:47 +05301088 {
Ed Tanous6c51eab2021-06-03 12:30:29 -07001089 // Disable the service first and update the rest of
1090 // the properties.
1091 handleServiceEnablePatch(false, asyncResp, serverT, dbusObjectPath);
Ratan Gupta8a07d282019-03-16 08:33:47 +05301092 }
Ed Tanous6c51eab2021-06-03 12:30:29 -07001093
Ratan Gupta8a07d282019-03-16 08:33:47 +05301094 if (serviceAddressList)
1095 {
Ed Tanous6c51eab2021-06-03 12:30:29 -07001096 handleServiceAddressPatch(*serviceAddressList, asyncResp, serverT,
1097 dbusObjectPath);
Ratan Gupta8a07d282019-03-16 08:33:47 +05301098 }
Ed Tanous6c51eab2021-06-03 12:30:29 -07001099 if (userName)
1100 {
1101 handleUserNamePatch(*userName, asyncResp, serverT, dbusObjectPath);
1102 }
1103 if (password)
1104 {
1105 handlePasswordPatch(*password, asyncResp, serverT, dbusObjectPath);
1106 }
1107
Ratan Gupta8a07d282019-03-16 08:33:47 +05301108 if (baseDNList)
1109 {
Ed Tanous6c51eab2021-06-03 12:30:29 -07001110 handleBaseDNPatch(*baseDNList, asyncResp, serverT, dbusObjectPath);
1111 }
1112 if (userNameAttribute)
1113 {
1114 handleUserNameAttrPatch(*userNameAttribute, asyncResp, serverT,
1115 dbusObjectPath);
1116 }
1117 if (groupsAttribute)
1118 {
1119 handleGroupNameAttrPatch(*groupsAttribute, asyncResp, serverT,
1120 dbusObjectPath);
1121 }
1122 if (serviceEnabled)
1123 {
1124 // if user has given the value as true then enable
1125 // the service. if user has given false then no-op
1126 // as service is already stopped.
1127 if (*serviceEnabled)
Ratan Gupta8a07d282019-03-16 08:33:47 +05301128 {
Ed Tanous6c51eab2021-06-03 12:30:29 -07001129 handleServiceEnablePatch(*serviceEnabled, asyncResp, serverT,
1130 dbusObjectPath);
Ratan Gupta8a07d282019-03-16 08:33:47 +05301131 }
1132 }
jayaprakash Mutyala96200602020-04-08 11:09:10 +00001133 else
1134 {
Ed Tanous6c51eab2021-06-03 12:30:29 -07001135 // if user has not given the service enabled value
1136 // then revert it to the same state as it was
1137 // before.
1138 handleServiceEnablePatch(confData.serviceEnabled, asyncResp,
1139 serverT, dbusObjectPath);
jayaprakash Mutyala96200602020-04-08 11:09:10 +00001140 }
Ed Tanous04ae99e2018-09-20 15:54:36 -07001141
Ed Tanous6c51eab2021-06-03 12:30:29 -07001142 if (remoteRoleMapData)
1143 {
1144 handleRoleMapPatch(asyncResp, confData.groupRoleList, serverT,
1145 *remoteRoleMapData);
1146 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001147 });
Ed Tanous6c51eab2021-06-03 12:30:29 -07001148}
1149
1150inline void updateUserProperties(std::shared_ptr<bmcweb::AsyncResp> asyncResp,
1151 const std::string& username,
Ed Tanous618c14b2022-06-30 17:44:25 -07001152 const std::optional<std::string>& password,
1153 const std::optional<bool>& enabled,
1154 const std::optional<std::string>& roleId,
1155 const std::optional<bool>& locked)
Ed Tanous6c51eab2021-06-03 12:30:29 -07001156{
P Dheeraj Srujan Kumarb477fd42021-12-16 07:17:51 +05301157 sdbusplus::message::object_path tempObjPath(rootUserDbusPath);
1158 tempObjPath /= username;
1159 std::string dbusObjectPath(tempObjPath);
Ed Tanous6c51eab2021-06-03 12:30:29 -07001160
1161 dbus::utility::checkDbusPathExists(
Ed Tanous618c14b2022-06-30 17:44:25 -07001162 dbusObjectPath, [dbusObjectPath, username, password, roleId, enabled,
1163 locked, asyncResp{std::move(asyncResp)}](int rc) {
1164 if (rc <= 0)
Ed Tanous6c51eab2021-06-03 12:30:29 -07001165 {
Jiaqing Zhaod8a5d5d2022-08-05 16:21:51 +08001166 messages::resourceNotFound(asyncResp->res, "ManagerAccount",
1167 username);
Ed Tanous6c51eab2021-06-03 12:30:29 -07001168 return;
1169 }
Ed Tanous6c51eab2021-06-03 12:30:29 -07001170
Ed Tanous618c14b2022-06-30 17:44:25 -07001171 if (password)
1172 {
1173 int retval = pamUpdatePassword(username, *password);
1174
1175 if (retval == PAM_USER_UNKNOWN)
1176 {
1177 messages::resourceNotFound(asyncResp->res, "ManagerAccount",
1178 username);
1179 }
1180 else if (retval == PAM_AUTHTOK_ERR)
1181 {
1182 // If password is invalid
1183 messages::propertyValueFormatError(asyncResp->res,
1184 *password, "Password");
1185 BMCWEB_LOG_ERROR << "pamUpdatePassword Failed";
1186 }
1187 else if (retval != PAM_SUCCESS)
1188 {
1189 messages::internalError(asyncResp->res);
1190 return;
1191 }
1192 else
1193 {
1194 messages::success(asyncResp->res);
1195 }
1196 }
1197
1198 if (enabled)
1199 {
1200 crow::connections::systemBus->async_method_call(
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001201 [asyncResp](const boost::system::error_code& ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001202 if (ec)
Ed Tanous04ae99e2018-09-20 15:54:36 -07001203 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001204 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
Ayushi Smriti599c71d2019-08-23 17:43:18 +00001205 messages::internalError(asyncResp->res);
Ed Tanous04ae99e2018-09-20 15:54:36 -07001206 return;
1207 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001208 messages::success(asyncResp->res);
1209 return;
Ed Tanous618c14b2022-06-30 17:44:25 -07001210 },
1211 "xyz.openbmc_project.User.Manager", dbusObjectPath,
1212 "org.freedesktop.DBus.Properties", "Set",
1213 "xyz.openbmc_project.User.Attributes", "UserEnabled",
1214 dbus::utility::DbusVariantType{*enabled});
Ed Tanous002d39b2022-05-31 08:59:27 -07001215 }
Ed Tanous04ae99e2018-09-20 15:54:36 -07001216
Ed Tanous618c14b2022-06-30 17:44:25 -07001217 if (roleId)
1218 {
1219 std::string priv = getPrivilegeFromRoleId(*roleId);
1220 if (priv.empty())
1221 {
1222 messages::propertyValueNotInList(asyncResp->res, *roleId,
1223 "RoleId");
1224 return;
1225 }
1226
1227 crow::connections::systemBus->async_method_call(
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001228 [asyncResp](const boost::system::error_code& ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001229 if (ec)
Ed Tanous04ae99e2018-09-20 15:54:36 -07001230 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001231 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
1232 messages::internalError(asyncResp->res);
Ed Tanous6c51eab2021-06-03 12:30:29 -07001233 return;
1234 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001235 messages::success(asyncResp->res);
Ed Tanous618c14b2022-06-30 17:44:25 -07001236 },
1237 "xyz.openbmc_project.User.Manager", dbusObjectPath,
1238 "org.freedesktop.DBus.Properties", "Set",
1239 "xyz.openbmc_project.User.Attributes", "UserPrivilege",
1240 dbus::utility::DbusVariantType{priv});
Ed Tanous6c51eab2021-06-03 12:30:29 -07001241 }
1242
Ed Tanous618c14b2022-06-30 17:44:25 -07001243 if (locked)
1244 {
1245 // admin can unlock the account which is locked by
1246 // successive authentication failures but admin should
1247 // not be allowed to lock an account.
1248 if (*locked)
1249 {
1250 messages::propertyValueNotInList(asyncResp->res, "true",
1251 "Locked");
1252 return;
1253 }
1254
1255 crow::connections::systemBus->async_method_call(
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001256 [asyncResp](const boost::system::error_code& ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001257 if (ec)
Ed Tanous6c51eab2021-06-03 12:30:29 -07001258 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001259 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
1260 messages::internalError(asyncResp->res);
Ed Tanous04ae99e2018-09-20 15:54:36 -07001261 return;
1262 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001263 messages::success(asyncResp->res);
1264 return;
Ed Tanous618c14b2022-06-30 17:44:25 -07001265 },
1266 "xyz.openbmc_project.User.Manager", dbusObjectPath,
1267 "org.freedesktop.DBus.Properties", "Set",
1268 "xyz.openbmc_project.User.Attributes",
1269 "UserLockedForFailedAttempt",
1270 dbus::utility::DbusVariantType{*locked});
1271 }
Ed Tanous6c51eab2021-06-03 12:30:29 -07001272 });
1273}
Ed Tanousb9b2e0b2018-09-13 13:47:50 -07001274
Ed Tanous4c7d4d32022-07-07 15:29:35 -07001275inline void handleAccountServiceHead(
1276 App& app, const crow::Request& req,
1277 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Ed Tanous1ef4c342022-05-12 16:12:36 -07001278{
1279 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1280 {
1281 return;
1282 }
Ed Tanous4c7d4d32022-07-07 15:29:35 -07001283 asyncResp->res.addHeader(
1284 boost::beast::http::field::link,
1285 "</redfish/v1/JsonSchemas/AccountService/AccountService.json>; rel=describedby");
1286}
1287
1288inline void
1289 handleAccountServiceGet(App& app, const crow::Request& req,
1290 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1291{
Jiaqing Zhaoafd369c2023-03-07 15:12:22 +08001292 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1293 {
1294 return;
1295 }
1296 asyncResp->res.addHeader(
1297 boost::beast::http::field::link,
1298 "</redfish/v1/JsonSchemas/AccountService/AccountService.json>; rel=describedby");
1299
Ed Tanous1ef4c342022-05-12 16:12:36 -07001300 const persistent_data::AuthConfigMethods& authMethodsConfig =
1301 persistent_data::SessionStore::getInstance().getAuthMethodsConfig();
1302
1303 nlohmann::json& json = asyncResp->res.jsonValue;
1304 json["@odata.id"] = "/redfish/v1/AccountService";
1305 json["@odata.type"] = "#AccountService."
1306 "v1_10_0.AccountService";
1307 json["Id"] = "AccountService";
1308 json["Name"] = "Account Service";
1309 json["Description"] = "Account Service";
1310 json["ServiceEnabled"] = true;
1311 json["MaxPasswordLength"] = 20;
1312 json["Accounts"]["@odata.id"] = "/redfish/v1/AccountService/Accounts";
1313 json["Roles"]["@odata.id"] = "/redfish/v1/AccountService/Roles";
1314 json["Oem"]["OpenBMC"]["@odata.type"] =
Ed Tanous5b5574a2022-09-26 19:53:36 -07001315 "#OpenBMCAccountService.v1_0_0.AccountService";
Ed Tanous1ef4c342022-05-12 16:12:36 -07001316 json["Oem"]["OpenBMC"]["@odata.id"] =
1317 "/redfish/v1/AccountService#/Oem/OpenBMC";
1318 json["Oem"]["OpenBMC"]["AuthMethods"]["BasicAuth"] =
1319 authMethodsConfig.basic;
1320 json["Oem"]["OpenBMC"]["AuthMethods"]["SessionToken"] =
1321 authMethodsConfig.sessionToken;
1322 json["Oem"]["OpenBMC"]["AuthMethods"]["XToken"] = authMethodsConfig.xtoken;
1323 json["Oem"]["OpenBMC"]["AuthMethods"]["Cookie"] = authMethodsConfig.cookie;
1324 json["Oem"]["OpenBMC"]["AuthMethods"]["TLS"] = authMethodsConfig.tls;
1325
1326 // /redfish/v1/AccountService/LDAP/Certificates is something only
1327 // ConfigureManager can access then only display when the user has
1328 // permissions ConfigureManager
1329 Privileges effectiveUserPrivileges =
1330 redfish::getUserPrivileges(req.userRole);
1331
1332 if (isOperationAllowedWithPrivileges({{"ConfigureManager"}},
1333 effectiveUserPrivileges))
1334 {
1335 asyncResp->res.jsonValue["LDAP"]["Certificates"]["@odata.id"] =
1336 "/redfish/v1/AccountService/LDAP/Certificates";
1337 }
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001338 sdbusplus::asio::getAllProperties(
1339 *crow::connections::systemBus, "xyz.openbmc_project.User.Manager",
1340 "/xyz/openbmc_project/user", "xyz.openbmc_project.User.AccountPolicy",
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001341 [asyncResp](const boost::system::error_code& ec,
Ed Tanous1ef4c342022-05-12 16:12:36 -07001342 const dbus::utility::DBusPropertiesMap& propertiesList) {
1343 if (ec)
1344 {
1345 messages::internalError(asyncResp->res);
1346 return;
1347 }
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001348
Ed Tanous1ef4c342022-05-12 16:12:36 -07001349 BMCWEB_LOG_DEBUG << "Got " << propertiesList.size()
1350 << "properties for AccountService";
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001351
1352 const uint8_t* minPasswordLength = nullptr;
1353 const uint32_t* accountUnlockTimeout = nullptr;
1354 const uint16_t* maxLoginAttemptBeforeLockout = nullptr;
1355
1356 const bool success = sdbusplus::unpackPropertiesNoThrow(
1357 dbus_utils::UnpackErrorPrinter(), propertiesList,
1358 "MinPasswordLength", minPasswordLength, "AccountUnlockTimeout",
1359 accountUnlockTimeout, "MaxLoginAttemptBeforeLockout",
1360 maxLoginAttemptBeforeLockout);
1361
1362 if (!success)
Ed Tanous1ef4c342022-05-12 16:12:36 -07001363 {
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001364 messages::internalError(asyncResp->res);
1365 return;
Ed Tanous1ef4c342022-05-12 16:12:36 -07001366 }
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001367
1368 if (minPasswordLength != nullptr)
1369 {
1370 asyncResp->res.jsonValue["MinPasswordLength"] = *minPasswordLength;
1371 }
1372
1373 if (accountUnlockTimeout != nullptr)
1374 {
1375 asyncResp->res.jsonValue["AccountLockoutDuration"] =
1376 *accountUnlockTimeout;
1377 }
1378
1379 if (maxLoginAttemptBeforeLockout != nullptr)
1380 {
1381 asyncResp->res.jsonValue["AccountLockoutThreshold"] =
1382 *maxLoginAttemptBeforeLockout;
1383 }
1384 });
Ed Tanous1ef4c342022-05-12 16:12:36 -07001385
Ed Tanous02cad962022-06-30 16:50:15 -07001386 auto callback = [asyncResp](bool success, const LDAPConfigData& confData,
Ed Tanous1ef4c342022-05-12 16:12:36 -07001387 const std::string& ldapType) {
1388 if (!success)
1389 {
1390 return;
1391 }
1392 parseLDAPConfigData(asyncResp->res.jsonValue, confData, ldapType);
1393 };
1394
1395 getLDAPConfigData("LDAP", callback);
1396 getLDAPConfigData("ActiveDirectory", callback);
1397}
1398
1399inline void handleAccountServicePatch(
1400 App& app, const crow::Request& req,
1401 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1402{
1403 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1404 {
1405 return;
1406 }
1407 std::optional<uint32_t> unlockTimeout;
1408 std::optional<uint16_t> lockoutThreshold;
1409 std::optional<uint8_t> minPasswordLength;
1410 std::optional<uint16_t> maxPasswordLength;
1411 std::optional<nlohmann::json> ldapObject;
1412 std::optional<nlohmann::json> activeDirectoryObject;
1413 std::optional<nlohmann::json> oemObject;
1414
1415 if (!json_util::readJsonPatch(
1416 req, asyncResp->res, "AccountLockoutDuration", unlockTimeout,
1417 "AccountLockoutThreshold", lockoutThreshold, "MaxPasswordLength",
1418 maxPasswordLength, "MinPasswordLength", minPasswordLength, "LDAP",
1419 ldapObject, "ActiveDirectory", activeDirectoryObject, "Oem",
1420 oemObject))
1421 {
1422 return;
1423 }
1424
1425 if (minPasswordLength)
1426 {
1427 crow::connections::systemBus->async_method_call(
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001428 [asyncResp](const boost::system::error_code& ec) {
Ed Tanous1ef4c342022-05-12 16:12:36 -07001429 if (ec)
1430 {
1431 messages::internalError(asyncResp->res);
1432 return;
1433 }
1434 messages::success(asyncResp->res);
1435 },
1436 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
1437 "org.freedesktop.DBus.Properties", "Set",
1438 "xyz.openbmc_project.User.AccountPolicy", "MinPasswordLength",
1439 dbus::utility::DbusVariantType(*minPasswordLength));
1440 }
1441
1442 if (maxPasswordLength)
1443 {
1444 messages::propertyNotWritable(asyncResp->res, "MaxPasswordLength");
1445 }
1446
1447 if (ldapObject)
1448 {
1449 handleLDAPPatch(*ldapObject, asyncResp, "LDAP");
1450 }
1451
1452 if (std::optional<nlohmann::json> oemOpenBMCObject;
1453 oemObject && json_util::readJson(*oemObject, asyncResp->res, "OpenBMC",
1454 oemOpenBMCObject))
1455 {
1456 if (std::optional<nlohmann::json> authMethodsObject;
1457 oemOpenBMCObject &&
1458 json_util::readJson(*oemOpenBMCObject, asyncResp->res,
1459 "AuthMethods", authMethodsObject))
1460 {
1461 if (authMethodsObject)
1462 {
1463 handleAuthMethodsPatch(*authMethodsObject, asyncResp);
1464 }
1465 }
1466 }
1467
1468 if (activeDirectoryObject)
1469 {
1470 handleLDAPPatch(*activeDirectoryObject, asyncResp, "ActiveDirectory");
1471 }
1472
1473 if (unlockTimeout)
1474 {
1475 crow::connections::systemBus->async_method_call(
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001476 [asyncResp](const boost::system::error_code& ec) {
Ed Tanous1ef4c342022-05-12 16:12:36 -07001477 if (ec)
1478 {
1479 messages::internalError(asyncResp->res);
1480 return;
1481 }
1482 messages::success(asyncResp->res);
1483 },
1484 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
1485 "org.freedesktop.DBus.Properties", "Set",
1486 "xyz.openbmc_project.User.AccountPolicy", "AccountUnlockTimeout",
1487 dbus::utility::DbusVariantType(*unlockTimeout));
1488 }
1489 if (lockoutThreshold)
1490 {
1491 crow::connections::systemBus->async_method_call(
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001492 [asyncResp](const boost::system::error_code& ec) {
Ed Tanous1ef4c342022-05-12 16:12:36 -07001493 if (ec)
1494 {
1495 messages::internalError(asyncResp->res);
1496 return;
1497 }
1498 messages::success(asyncResp->res);
1499 },
1500 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
1501 "org.freedesktop.DBus.Properties", "Set",
1502 "xyz.openbmc_project.User.AccountPolicy",
1503 "MaxLoginAttemptBeforeLockout",
1504 dbus::utility::DbusVariantType(*lockoutThreshold));
1505 }
1506}
1507
Ed Tanous4c7d4d32022-07-07 15:29:35 -07001508inline void handleAccountCollectionHead(
Ed Tanous1ef4c342022-05-12 16:12:36 -07001509 App& app, const crow::Request& req,
1510 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1511{
1512 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1513 {
1514 return;
1515 }
Ed Tanous4c7d4d32022-07-07 15:29:35 -07001516 asyncResp->res.addHeader(
1517 boost::beast::http::field::link,
1518 "</redfish/v1/JsonSchemas/ManagerAccountCollection.json>; rel=describedby");
1519}
1520
1521inline void handleAccountCollectionGet(
1522 App& app, const crow::Request& req,
1523 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1524{
Jiaqing Zhaoafd369c2023-03-07 15:12:22 +08001525 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1526 {
1527 return;
1528 }
1529 asyncResp->res.addHeader(
1530 boost::beast::http::field::link,
1531 "</redfish/v1/JsonSchemas/ManagerAccountCollection.json>; rel=describedby");
Ed Tanous1ef4c342022-05-12 16:12:36 -07001532
1533 asyncResp->res.jsonValue["@odata.id"] =
1534 "/redfish/v1/AccountService/Accounts";
1535 asyncResp->res.jsonValue["@odata.type"] = "#ManagerAccountCollection."
1536 "ManagerAccountCollection";
1537 asyncResp->res.jsonValue["Name"] = "Accounts Collection";
1538 asyncResp->res.jsonValue["Description"] = "BMC User Accounts";
1539
1540 Privileges effectiveUserPrivileges =
1541 redfish::getUserPrivileges(req.userRole);
1542
1543 std::string thisUser;
1544 if (req.session)
1545 {
1546 thisUser = req.session->username;
1547 }
1548 crow::connections::systemBus->async_method_call(
1549 [asyncResp, thisUser, effectiveUserPrivileges](
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001550 const boost::system::error_code& ec,
Ed Tanous1ef4c342022-05-12 16:12:36 -07001551 const dbus::utility::ManagedObjectType& users) {
1552 if (ec)
1553 {
1554 messages::internalError(asyncResp->res);
1555 return;
1556 }
1557
1558 bool userCanSeeAllAccounts =
1559 effectiveUserPrivileges.isSupersetOf({"ConfigureUsers"});
1560
1561 bool userCanSeeSelf =
1562 effectiveUserPrivileges.isSupersetOf({"ConfigureSelf"});
1563
1564 nlohmann::json& memberArray = asyncResp->res.jsonValue["Members"];
1565 memberArray = nlohmann::json::array();
1566
1567 for (const auto& userpath : users)
1568 {
1569 std::string user = userpath.first.filename();
1570 if (user.empty())
1571 {
1572 messages::internalError(asyncResp->res);
1573 BMCWEB_LOG_ERROR << "Invalid firmware ID";
1574
1575 return;
1576 }
1577
1578 // As clarified by Redfish here:
1579 // https://redfishforum.com/thread/281/manageraccountcollection-change-allows-account-enumeration
1580 // Users without ConfigureUsers, only see their own
1581 // account. Users with ConfigureUsers, see all
1582 // accounts.
1583 if (userCanSeeAllAccounts || (thisUser == user && userCanSeeSelf))
1584 {
1585 nlohmann::json::object_t member;
Patrick Williams89492a12023-05-10 07:51:34 -05001586 member["@odata.id"] = "/redfish/v1/AccountService/Accounts/" +
1587 user;
Patrick Williamsb2ba3072023-05-12 10:27:39 -05001588 memberArray.emplace_back(std::move(member));
Ed Tanous1ef4c342022-05-12 16:12:36 -07001589 }
1590 }
1591 asyncResp->res.jsonValue["Members@odata.count"] = memberArray.size();
1592 },
1593 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
1594 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
1595}
1596
Ninad Palsule97e90da2023-05-17 14:04:52 -05001597inline void processAfterCreateUser(
1598 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1599 const std::string& username, const std::string& password,
1600 const boost::system::error_code& ec, sdbusplus::message_t& m)
1601{
1602 if (ec)
1603 {
1604 userErrorMessageHandler(m.get_error(), asyncResp, username, "");
1605 return;
1606 }
1607
1608 if (pamUpdatePassword(username, password) != PAM_SUCCESS)
1609 {
1610 // At this point we have a user that's been
1611 // created, but the password set
1612 // failed.Something is wrong, so delete the user
1613 // that we've already created
1614 sdbusplus::message::object_path tempObjPath(rootUserDbusPath);
1615 tempObjPath /= username;
1616 const std::string userPath(tempObjPath);
1617
1618 crow::connections::systemBus->async_method_call(
1619 [asyncResp, password](const boost::system::error_code& ec3) {
1620 if (ec3)
1621 {
1622 messages::internalError(asyncResp->res);
1623 return;
1624 }
1625
1626 // If password is invalid
1627 messages::propertyValueFormatError(asyncResp->res, password,
1628 "Password");
1629 },
1630 "xyz.openbmc_project.User.Manager", userPath,
1631 "xyz.openbmc_project.Object.Delete", "Delete");
1632
1633 BMCWEB_LOG_ERROR << "pamUpdatePassword Failed";
1634 return;
1635 }
1636
1637 messages::created(asyncResp->res);
1638 asyncResp->res.addHeader("Location",
1639 "/redfish/v1/AccountService/Accounts/" + username);
1640}
1641
1642inline void processAfterGetAllGroups(
1643 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1644 const std::string& username, const std::string& password,
1645 const std::optional<std::string>& roleId, std::optional<bool> enabled,
1646 const std::vector<std::string>& allGroupsList)
1647
1648{
1649 crow::connections::systemBus->async_method_call(
1650 [asyncResp, username, password](const boost::system::error_code& ec2,
1651 sdbusplus::message_t& m) {
1652 processAfterCreateUser(asyncResp, username, password, ec2, m);
1653 },
1654 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
1655 "xyz.openbmc_project.User.Manager", "CreateUser", username,
1656 allGroupsList, *roleId, *enabled);
1657}
1658
Ed Tanous1ef4c342022-05-12 16:12:36 -07001659inline void handleAccountCollectionPost(
1660 App& app, const crow::Request& req,
1661 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1662{
1663 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1664 {
1665 return;
1666 }
1667 std::string username;
1668 std::string password;
1669 std::optional<std::string> roleId("User");
1670 std::optional<bool> enabled = true;
1671 if (!json_util::readJsonPatch(req, asyncResp->res, "UserName", username,
1672 "Password", password, "RoleId", roleId,
1673 "Enabled", enabled))
1674 {
1675 return;
1676 }
1677
1678 std::string priv = getPrivilegeFromRoleId(*roleId);
1679 if (priv.empty())
1680 {
1681 messages::propertyValueNotInList(asyncResp->res, *roleId, "RoleId");
1682 return;
1683 }
Asmitha Karunanithi239adf82022-03-25 02:59:03 -05001684 roleId = priv;
Ed Tanous1ef4c342022-05-12 16:12:36 -07001685
1686 // Reading AllGroups property
1687 sdbusplus::asio::getProperty<std::vector<std::string>>(
1688 *crow::connections::systemBus, "xyz.openbmc_project.User.Manager",
1689 "/xyz/openbmc_project/user", "xyz.openbmc_project.User.Manager",
1690 "AllGroups",
1691 [asyncResp, username, password{std::move(password)}, roleId,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001692 enabled](const boost::system::error_code& ec,
Ed Tanous1ef4c342022-05-12 16:12:36 -07001693 const std::vector<std::string>& allGroupsList) {
1694 if (ec)
1695 {
1696 BMCWEB_LOG_DEBUG << "ERROR with async_method_call";
1697 messages::internalError(asyncResp->res);
1698 return;
1699 }
1700
1701 if (allGroupsList.empty())
1702 {
1703 messages::internalError(asyncResp->res);
1704 return;
1705 }
1706
Ninad Palsule97e90da2023-05-17 14:04:52 -05001707 processAfterGetAllGroups(asyncResp, username, password, roleId, enabled,
1708 allGroupsList);
Ed Tanous1ef4c342022-05-12 16:12:36 -07001709 });
1710}
1711
1712inline void
Ed Tanous4c7d4d32022-07-07 15:29:35 -07001713 handleAccountHead(App& app, const crow::Request& req,
1714 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1715 const std::string& /*accountName*/)
Ed Tanous1ef4c342022-05-12 16:12:36 -07001716{
1717 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1718 {
1719 return;
1720 }
Ed Tanous4c7d4d32022-07-07 15:29:35 -07001721 asyncResp->res.addHeader(
1722 boost::beast::http::field::link,
1723 "</redfish/v1/JsonSchemas/ManagerAccount/ManagerAccount.json>; rel=describedby");
1724}
Jiaqing Zhaoafd369c2023-03-07 15:12:22 +08001725
Ed Tanous4c7d4d32022-07-07 15:29:35 -07001726inline void
1727 handleAccountGet(App& app, const crow::Request& req,
1728 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1729 const std::string& accountName)
1730{
Jiaqing Zhaoafd369c2023-03-07 15:12:22 +08001731 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1732 {
1733 return;
1734 }
1735 asyncResp->res.addHeader(
1736 boost::beast::http::field::link,
1737 "</redfish/v1/JsonSchemas/ManagerAccount/ManagerAccount.json>; rel=describedby");
1738
Ed Tanous1ef4c342022-05-12 16:12:36 -07001739#ifdef BMCWEB_INSECURE_DISABLE_AUTHENTICATION
1740 // If authentication is disabled, there are no user accounts
Jiaqing Zhaod8a5d5d2022-08-05 16:21:51 +08001741 messages::resourceNotFound(asyncResp->res, "ManagerAccount", accountName);
Ed Tanous1ef4c342022-05-12 16:12:36 -07001742 return;
Ed Tanous1ef4c342022-05-12 16:12:36 -07001743#endif // BMCWEB_INSECURE_DISABLE_AUTHENTICATION
Jiaqing Zhaoafd369c2023-03-07 15:12:22 +08001744
Ed Tanous1ef4c342022-05-12 16:12:36 -07001745 if (req.session == nullptr)
1746 {
1747 messages::internalError(asyncResp->res);
1748 return;
1749 }
1750 if (req.session->username != accountName)
1751 {
1752 // At this point we've determined that the user is trying to
1753 // modify a user that isn't them. We need to verify that they
1754 // have permissions to modify other users, so re-run the auth
1755 // check with the same permissions, minus ConfigureSelf.
1756 Privileges effectiveUserPrivileges =
1757 redfish::getUserPrivileges(req.userRole);
1758 Privileges requiredPermissionsToChangeNonSelf = {"ConfigureUsers",
1759 "ConfigureManager"};
1760 if (!effectiveUserPrivileges.isSupersetOf(
1761 requiredPermissionsToChangeNonSelf))
1762 {
1763 BMCWEB_LOG_DEBUG << "GET Account denied access";
1764 messages::insufficientPrivilege(asyncResp->res);
1765 return;
1766 }
1767 }
1768
1769 crow::connections::systemBus->async_method_call(
1770 [asyncResp,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001771 accountName](const boost::system::error_code& ec,
Ed Tanous1ef4c342022-05-12 16:12:36 -07001772 const dbus::utility::ManagedObjectType& users) {
1773 if (ec)
1774 {
1775 messages::internalError(asyncResp->res);
1776 return;
1777 }
1778 const auto userIt = std::find_if(
1779 users.begin(), users.end(),
1780 [accountName](
1781 const std::pair<sdbusplus::message::object_path,
1782 dbus::utility::DBusInteracesMap>& user) {
1783 return accountName == user.first.filename();
1784 });
1785
1786 if (userIt == users.end())
1787 {
1788 messages::resourceNotFound(asyncResp->res, "ManagerAccount",
1789 accountName);
1790 return;
1791 }
1792
1793 asyncResp->res.jsonValue["@odata.type"] =
1794 "#ManagerAccount.v1_4_0.ManagerAccount";
1795 asyncResp->res.jsonValue["Name"] = "User Account";
1796 asyncResp->res.jsonValue["Description"] = "User Account";
1797 asyncResp->res.jsonValue["Password"] = nullptr;
Ed Tanous1ef4c342022-05-12 16:12:36 -07001798
1799 for (const auto& interface : userIt->second)
1800 {
1801 if (interface.first == "xyz.openbmc_project.User.Attributes")
1802 {
1803 for (const auto& property : interface.second)
1804 {
1805 if (property.first == "UserEnabled")
1806 {
1807 const bool* userEnabled =
1808 std::get_if<bool>(&property.second);
1809 if (userEnabled == nullptr)
1810 {
1811 BMCWEB_LOG_ERROR << "UserEnabled wasn't a bool";
1812 messages::internalError(asyncResp->res);
1813 return;
1814 }
1815 asyncResp->res.jsonValue["Enabled"] = *userEnabled;
1816 }
1817 else if (property.first == "UserLockedForFailedAttempt")
1818 {
1819 const bool* userLocked =
1820 std::get_if<bool>(&property.second);
1821 if (userLocked == nullptr)
1822 {
1823 BMCWEB_LOG_ERROR << "UserLockedForF"
1824 "ailedAttempt "
1825 "wasn't a bool";
1826 messages::internalError(asyncResp->res);
1827 return;
1828 }
1829 asyncResp->res.jsonValue["Locked"] = *userLocked;
1830 asyncResp->res
1831 .jsonValue["Locked@Redfish.AllowableValues"] = {
1832 "false"}; // can only unlock accounts
1833 }
1834 else if (property.first == "UserPrivilege")
1835 {
1836 const std::string* userPrivPtr =
1837 std::get_if<std::string>(&property.second);
1838 if (userPrivPtr == nullptr)
1839 {
1840 BMCWEB_LOG_ERROR << "UserPrivilege wasn't a "
1841 "string";
1842 messages::internalError(asyncResp->res);
1843 return;
1844 }
1845 std::string role = getRoleIdFromPrivilege(*userPrivPtr);
1846 if (role.empty())
1847 {
1848 BMCWEB_LOG_ERROR << "Invalid user role";
1849 messages::internalError(asyncResp->res);
1850 return;
1851 }
1852 asyncResp->res.jsonValue["RoleId"] = role;
1853
1854 nlohmann::json& roleEntry =
1855 asyncResp->res.jsonValue["Links"]["Role"];
1856 roleEntry["@odata.id"] =
1857 "/redfish/v1/AccountService/Roles/" + role;
1858 }
1859 else if (property.first == "UserPasswordExpired")
1860 {
1861 const bool* userPasswordExpired =
1862 std::get_if<bool>(&property.second);
1863 if (userPasswordExpired == nullptr)
1864 {
1865 BMCWEB_LOG_ERROR
1866 << "UserPasswordExpired wasn't a bool";
1867 messages::internalError(asyncResp->res);
1868 return;
1869 }
1870 asyncResp->res.jsonValue["PasswordChangeRequired"] =
1871 *userPasswordExpired;
1872 }
Abhishek Patelc7229812022-02-01 10:07:15 -06001873 else if (property.first == "UserGroups")
1874 {
1875 const std::vector<std::string>* userGroups =
1876 std::get_if<std::vector<std::string>>(
1877 &property.second);
1878 if (userGroups == nullptr)
1879 {
1880 BMCWEB_LOG_ERROR
1881 << "userGroups wasn't a string vector";
1882 messages::internalError(asyncResp->res);
1883 return;
1884 }
1885 if (!translateUserGroup(*userGroups, asyncResp->res))
1886 {
1887 BMCWEB_LOG_ERROR << "userGroups mapping failed";
1888 messages::internalError(asyncResp->res);
1889 return;
1890 }
1891 }
Ed Tanous1ef4c342022-05-12 16:12:36 -07001892 }
1893 }
1894 }
1895
1896 asyncResp->res.jsonValue["@odata.id"] =
1897 "/redfish/v1/AccountService/Accounts/" + accountName;
1898 asyncResp->res.jsonValue["Id"] = accountName;
1899 asyncResp->res.jsonValue["UserName"] = accountName;
1900 },
1901 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
1902 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
1903}
1904
1905inline void
Gunnar Mills20fc3072023-01-27 15:13:36 -06001906 handleAccountDelete(App& app, const crow::Request& req,
1907 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1908 const std::string& username)
Ed Tanous1ef4c342022-05-12 16:12:36 -07001909{
1910 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1911 {
1912 return;
1913 }
1914
1915#ifdef BMCWEB_INSECURE_DISABLE_AUTHENTICATION
1916 // If authentication is disabled, there are no user accounts
Jiaqing Zhaod8a5d5d2022-08-05 16:21:51 +08001917 messages::resourceNotFound(asyncResp->res, "ManagerAccount", username);
Ed Tanous1ef4c342022-05-12 16:12:36 -07001918 return;
1919
1920#endif // BMCWEB_INSECURE_DISABLE_AUTHENTICATION
1921 sdbusplus::message::object_path tempObjPath(rootUserDbusPath);
1922 tempObjPath /= username;
1923 const std::string userPath(tempObjPath);
1924
1925 crow::connections::systemBus->async_method_call(
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001926 [asyncResp, username](const boost::system::error_code& ec) {
Ed Tanous1ef4c342022-05-12 16:12:36 -07001927 if (ec)
1928 {
Jiaqing Zhaod8a5d5d2022-08-05 16:21:51 +08001929 messages::resourceNotFound(asyncResp->res, "ManagerAccount",
Ed Tanous1ef4c342022-05-12 16:12:36 -07001930 username);
1931 return;
1932 }
1933
1934 messages::accountRemoved(asyncResp->res);
1935 },
1936 "xyz.openbmc_project.User.Manager", userPath,
1937 "xyz.openbmc_project.Object.Delete", "Delete");
1938}
1939
1940inline void
1941 handleAccountPatch(App& app, const crow::Request& req,
1942 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1943 const std::string& username)
1944{
1945 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1946 {
1947 return;
1948 }
1949#ifdef BMCWEB_INSECURE_DISABLE_AUTHENTICATION
1950 // If authentication is disabled, there are no user accounts
Jiaqing Zhaod8a5d5d2022-08-05 16:21:51 +08001951 messages::resourceNotFound(asyncResp->res, "ManagerAccount", username);
Ed Tanous1ef4c342022-05-12 16:12:36 -07001952 return;
1953
1954#endif // BMCWEB_INSECURE_DISABLE_AUTHENTICATION
1955 std::optional<std::string> newUserName;
1956 std::optional<std::string> password;
1957 std::optional<bool> enabled;
1958 std::optional<std::string> roleId;
1959 std::optional<bool> locked;
1960
1961 if (req.session == nullptr)
1962 {
1963 messages::internalError(asyncResp->res);
1964 return;
1965 }
1966
1967 Privileges effectiveUserPrivileges =
1968 redfish::getUserPrivileges(req.userRole);
1969 Privileges configureUsers = {"ConfigureUsers"};
1970 bool userHasConfigureUsers =
1971 effectiveUserPrivileges.isSupersetOf(configureUsers);
1972 if (userHasConfigureUsers)
1973 {
1974 // Users with ConfigureUsers can modify for all users
1975 if (!json_util::readJsonPatch(req, asyncResp->res, "UserName",
1976 newUserName, "Password", password,
1977 "RoleId", roleId, "Enabled", enabled,
1978 "Locked", locked))
1979 {
1980 return;
1981 }
1982 }
1983 else
1984 {
1985 // ConfigureSelf accounts can only modify their own account
1986 if (username != req.session->username)
1987 {
1988 messages::insufficientPrivilege(asyncResp->res);
1989 return;
1990 }
1991
1992 // ConfigureSelf accounts can only modify their password
1993 if (!json_util::readJsonPatch(req, asyncResp->res, "Password",
1994 password))
1995 {
1996 return;
1997 }
1998 }
1999
2000 // if user name is not provided in the patch method or if it
2001 // matches the user name in the URI, then we are treating it as
2002 // updating user properties other then username. If username
2003 // provided doesn't match the URI, then we are treating this as
2004 // user rename request.
2005 if (!newUserName || (newUserName.value() == username))
2006 {
2007 updateUserProperties(asyncResp, username, password, enabled, roleId,
2008 locked);
2009 return;
2010 }
2011 crow::connections::systemBus->async_method_call(
2012 [asyncResp, username, password(std::move(password)),
2013 roleId(std::move(roleId)), enabled, newUser{std::string(*newUserName)},
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08002014 locked](const boost::system::error_code& ec, sdbusplus::message_t& m) {
Ed Tanous1ef4c342022-05-12 16:12:36 -07002015 if (ec)
2016 {
2017 userErrorMessageHandler(m.get_error(), asyncResp, newUser,
2018 username);
2019 return;
2020 }
2021
2022 updateUserProperties(asyncResp, newUser, password, enabled, roleId,
2023 locked);
2024 },
2025 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
2026 "xyz.openbmc_project.User.Manager", "RenameUser", username,
2027 *newUserName);
2028}
2029
Ed Tanous6c51eab2021-06-03 12:30:29 -07002030inline void requestAccountServiceRoutes(App& app)
Ed Tanousb9b2e0b2018-09-13 13:47:50 -07002031{
Ed Tanous6c51eab2021-06-03 12:30:29 -07002032 BMCWEB_ROUTE(app, "/redfish/v1/AccountService/")
Ed Tanous4c7d4d32022-07-07 15:29:35 -07002033 .privileges(redfish::privileges::headAccountService)
2034 .methods(boost::beast::http::verb::head)(
2035 std::bind_front(handleAccountServiceHead, std::ref(app)));
2036
2037 BMCWEB_ROUTE(app, "/redfish/v1/AccountService/")
Ed Tanoused398212021-06-09 17:05:54 -07002038 .privileges(redfish::privileges::getAccountService)
Ed Tanous002d39b2022-05-31 08:59:27 -07002039 .methods(boost::beast::http::verb::get)(
Ed Tanous1ef4c342022-05-12 16:12:36 -07002040 std::bind_front(handleAccountServiceGet, std::ref(app)));
Ed Tanous6c51eab2021-06-03 12:30:29 -07002041
Ed Tanousf5ffd802021-07-19 10:55:33 -07002042 BMCWEB_ROUTE(app, "/redfish/v1/AccountService/")
Gunnar Mills1ec43ee2022-01-04 15:39:52 -06002043 .privileges(redfish::privileges::patchAccountService)
Ed Tanousf5ffd802021-07-19 10:55:33 -07002044 .methods(boost::beast::http::verb::patch)(
Ed Tanous1ef4c342022-05-12 16:12:36 -07002045 std::bind_front(handleAccountServicePatch, std::ref(app)));
Ed Tanousf5ffd802021-07-19 10:55:33 -07002046
Ed Tanous6c51eab2021-06-03 12:30:29 -07002047 BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/")
Ed Tanous4c7d4d32022-07-07 15:29:35 -07002048 .privileges(redfish::privileges::headManagerAccountCollection)
2049 .methods(boost::beast::http::verb::head)(
2050 std::bind_front(handleAccountCollectionHead, std::ref(app)));
2051
2052 BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/")
Ed Tanoused398212021-06-09 17:05:54 -07002053 .privileges(redfish::privileges::getManagerAccountCollection)
Ed Tanous6c51eab2021-06-03 12:30:29 -07002054 .methods(boost::beast::http::verb::get)(
Ed Tanous1ef4c342022-05-12 16:12:36 -07002055 std::bind_front(handleAccountCollectionGet, std::ref(app)));
Ed Tanous06e086d2018-09-19 17:19:52 -07002056
Ed Tanous6c51eab2021-06-03 12:30:29 -07002057 BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/")
Ed Tanoused398212021-06-09 17:05:54 -07002058 .privileges(redfish::privileges::postManagerAccountCollection)
Ed Tanous002d39b2022-05-31 08:59:27 -07002059 .methods(boost::beast::http::verb::post)(
Ed Tanous1ef4c342022-05-12 16:12:36 -07002060 std::bind_front(handleAccountCollectionPost, std::ref(app)));
Ed Tanous002d39b2022-05-31 08:59:27 -07002061
2062 BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/<str>/")
Ed Tanous4c7d4d32022-07-07 15:29:35 -07002063 .privileges(redfish::privileges::headManagerAccount)
2064 .methods(boost::beast::http::verb::head)(
2065 std::bind_front(handleAccountHead, std::ref(app)));
2066
2067 BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/<str>/")
Ed Tanous002d39b2022-05-31 08:59:27 -07002068 .privileges(redfish::privileges::getManagerAccount)
2069 .methods(boost::beast::http::verb::get)(
Ed Tanous1ef4c342022-05-12 16:12:36 -07002070 std::bind_front(handleAccountGet, std::ref(app)));
Ed Tanous6c51eab2021-06-03 12:30:29 -07002071
2072 BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002073 // TODO this privilege should be using the generated endpoints, but
2074 // because of the special handling of ConfigureSelf, it's not able to
2075 // yet
Ed Tanous6c51eab2021-06-03 12:30:29 -07002076 .privileges({{"ConfigureUsers"}, {"ConfigureSelf"}})
2077 .methods(boost::beast::http::verb::patch)(
Ed Tanous1ef4c342022-05-12 16:12:36 -07002078 std::bind_front(handleAccountPatch, std::ref(app)));
Ed Tanous6c51eab2021-06-03 12:30:29 -07002079
2080 BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002081 .privileges(redfish::privileges::deleteManagerAccount)
Ed Tanous6c51eab2021-06-03 12:30:29 -07002082 .methods(boost::beast::http::verb::delete_)(
Gunnar Mills20fc3072023-01-27 15:13:36 -06002083 std::bind_front(handleAccountDelete, std::ref(app)));
Ed Tanous6c51eab2021-06-03 12:30:29 -07002084}
Lewanczyk, Dawid88d16c92018-02-02 14:51:09 +01002085
Ed Tanous1abe55e2018-09-05 08:30:59 -07002086} // namespace redfish