blob: 0cef7a36a62fc70fef0287823eb9b2d2fe7ef822 [file] [log] [blame]
Lewanczyk, Dawid88d16c92018-02-02 14:51:09 +01001/*
2// Copyright (c) 2018 Intel Corporation
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15*/
16#pragma once
Lewanczyk, Dawid88d16c92018-02-02 14:51:09 +010017
John Edward Broadbent7e860f12021-04-08 15:57:16 -070018#include <app.hpp>
Ratan Gupta24c85422019-01-30 19:41:24 +053019#include <dbus_utility.hpp>
Ed Tanous65b0dc32018-09-19 16:04:03 -070020#include <error_messages.hpp>
Ed Tanousb9b2e0b2018-09-13 13:47:50 -070021#include <openbmc_dbus_rest.hpp>
Ed Tanous52cc1122020-07-18 13:51:21 -070022#include <persistent_data.hpp>
Ed Tanous45ca1b82022-03-25 13:07:27 -070023#include <query.hpp>
Ed Tanoused398212021-06-09 17:05:54 -070024#include <registries/privilege_registry.hpp>
Jonathan Doman1e1e5982021-06-11 09:36:17 -070025#include <sdbusplus/asio/property.hpp>
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +020026#include <sdbusplus/unpack_properties.hpp>
27#include <utils/dbus_utils.hpp>
Ed Tanousa8408792018-09-05 16:08:38 -070028#include <utils/json_utils.hpp>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050029
Abhishek Patelc7229812022-02-01 10:07:15 -060030#include <optional>
31#include <string>
32#include <vector>
33
Ed Tanous1abe55e2018-09-05 08:30:59 -070034namespace redfish
35{
Lewanczyk, Dawid88d16c92018-02-02 14:51:09 +010036
Ed Tanous23a21a12020-07-25 04:45:05 +000037constexpr const char* ldapConfigObjectName =
Ratan Gupta6973a582018-12-13 18:25:44 +053038 "/xyz/openbmc_project/user/ldap/openldap";
Ed Tanous2c70f802020-09-28 14:29:23 -070039constexpr const char* adConfigObject =
Ratan Guptaab828d72019-04-22 14:18:33 +053040 "/xyz/openbmc_project/user/ldap/active_directory";
41
P Dheeraj Srujan Kumarb477fd42021-12-16 07:17:51 +053042constexpr const char* rootUserDbusPath = "/xyz/openbmc_project/user/";
Ratan Gupta6973a582018-12-13 18:25:44 +053043constexpr const char* ldapRootObject = "/xyz/openbmc_project/user/ldap";
44constexpr const char* ldapDbusService = "xyz.openbmc_project.Ldap.Config";
45constexpr const char* ldapConfigInterface =
46 "xyz.openbmc_project.User.Ldap.Config";
47constexpr const char* ldapCreateInterface =
48 "xyz.openbmc_project.User.Ldap.Create";
49constexpr const char* ldapEnableInterface = "xyz.openbmc_project.Object.Enable";
Ratan Gupta06785242019-07-26 22:30:16 +053050constexpr const char* ldapPrivMapperInterface =
51 "xyz.openbmc_project.User.PrivilegeMapper";
Ratan Gupta6973a582018-12-13 18:25:44 +053052constexpr const char* dbusObjManagerIntf = "org.freedesktop.DBus.ObjectManager";
53constexpr const char* propertyInterface = "org.freedesktop.DBus.Properties";
54constexpr const char* mapperBusName = "xyz.openbmc_project.ObjectMapper";
55constexpr const char* mapperObjectPath = "/xyz/openbmc_project/object_mapper";
56constexpr const char* mapperIntf = "xyz.openbmc_project.ObjectMapper";
57
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -060058struct LDAPRoleMapData
59{
60 std::string groupName;
61 std::string privilege;
62};
63
Ratan Gupta6973a582018-12-13 18:25:44 +053064struct LDAPConfigData
65{
66 std::string uri{};
67 std::string bindDN{};
68 std::string baseDN{};
69 std::string searchScope{};
70 std::string serverType{};
71 bool serviceEnabled = false;
72 std::string userNameAttribute{};
73 std::string groupAttribute{};
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -060074 std::vector<std::pair<std::string, LDAPRoleMapData>> groupRoleList;
Ratan Gupta6973a582018-12-13 18:25:44 +053075};
76
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -060077inline std::string getRoleIdFromPrivilege(std::string_view role)
AppaRao Puli84e12cb2018-10-11 01:28:15 +053078{
79 if (role == "priv-admin")
80 {
81 return "Administrator";
82 }
Ed Tanous3174e4d2020-10-07 11:41:22 -070083 if (role == "priv-user")
AppaRao Puli84e12cb2018-10-11 01:28:15 +053084 {
AppaRao Pulic80fee52019-10-16 14:49:36 +053085 return "ReadOnly";
AppaRao Puli84e12cb2018-10-11 01:28:15 +053086 }
Ed Tanous3174e4d2020-10-07 11:41:22 -070087 if (role == "priv-operator")
AppaRao Puli84e12cb2018-10-11 01:28:15 +053088 {
89 return "Operator";
90 }
Ed Tanous26f69762022-01-25 09:49:11 -080091 if (role.empty() || (role == "priv-noaccess"))
jayaprakash Mutyalae9e6d242019-07-29 11:59:08 +000092 {
93 return "NoAccess";
94 }
AppaRao Puli84e12cb2018-10-11 01:28:15 +053095 return "";
96}
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -060097inline std::string getPrivilegeFromRoleId(std::string_view role)
AppaRao Puli84e12cb2018-10-11 01:28:15 +053098{
99 if (role == "Administrator")
100 {
101 return "priv-admin";
102 }
Ed Tanous3174e4d2020-10-07 11:41:22 -0700103 if (role == "ReadOnly")
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530104 {
105 return "priv-user";
106 }
Ed Tanous3174e4d2020-10-07 11:41:22 -0700107 if (role == "Operator")
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530108 {
109 return "priv-operator";
110 }
Ed Tanous26f69762022-01-25 09:49:11 -0800111 if ((role == "NoAccess") || (role.empty()))
jayaprakash Mutyalae9e6d242019-07-29 11:59:08 +0000112 {
113 return "priv-noaccess";
114 }
AppaRao Puli84e12cb2018-10-11 01:28:15 +0530115 return "";
116}
Ed Tanousb9b2e0b2018-09-13 13:47:50 -0700117
Abhishek Patelc7229812022-02-01 10:07:15 -0600118/**
119 * @brief Maps user group names retrieved from D-Bus object to
120 * Account Types.
121 *
122 * @param[in] userGroups List of User groups
123 * @param[out] res AccountTypes populated
124 *
125 * @return true in case of success, false if UserGroups contains
126 * invalid group name(s).
127 */
128inline bool translateUserGroup(const std::vector<std::string>& userGroups,
129 crow::Response& res)
130{
131 std::vector<std::string> accountTypes;
132 for (const auto& userGroup : userGroups)
133 {
134 if (userGroup == "redfish")
135 {
136 accountTypes.emplace_back("Redfish");
137 accountTypes.emplace_back("WebUI");
138 }
139 else if (userGroup == "ipmi")
140 {
141 accountTypes.emplace_back("IPMI");
142 }
143 else if (userGroup == "ssh")
144 {
145 accountTypes.emplace_back("HostConsole");
146 accountTypes.emplace_back("ManagerConsole");
147 }
148 else if (userGroup == "web")
149 {
150 // 'web' is one of the valid groups in the UserGroups property of
151 // the user account in the D-Bus object. This group is currently not
152 // doing anything, and is considered to be equivalent to 'redfish'.
153 // 'redfish' user group is mapped to 'Redfish'and 'WebUI'
154 // AccountTypes, so do nothing here...
155 }
156 else
157 {
158 // Invalid user group name. Caller throws an excption.
159 return false;
160 }
161 }
162
163 res.jsonValue["AccountTypes"] = std::move(accountTypes);
164 return true;
165}
166
zhanghch058d1b46d2021-04-01 11:18:24 +0800167inline void userErrorMessageHandler(
168 const sd_bus_error* e, const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
169 const std::string& newUser, const std::string& username)
jayaprakash Mutyala66b5ca72019-08-07 20:26:37 +0000170{
jayaprakash Mutyala66b5ca72019-08-07 20:26:37 +0000171 if (e == nullptr)
172 {
173 messages::internalError(asyncResp->res);
174 return;
175 }
176
Manojkiran Eda055806b2020-11-03 09:36:28 +0530177 const char* errorMessage = e->name;
jayaprakash Mutyala66b5ca72019-08-07 20:26:37 +0000178 if (strcmp(errorMessage,
179 "xyz.openbmc_project.User.Common.Error.UserNameExists") == 0)
180 {
Jiaqing Zhaod8a5d5d2022-08-05 16:21:51 +0800181 messages::resourceAlreadyExists(asyncResp->res, "ManagerAccount",
jayaprakash Mutyala66b5ca72019-08-07 20:26:37 +0000182 "UserName", newUser);
183 }
184 else if (strcmp(errorMessage, "xyz.openbmc_project.User.Common.Error."
185 "UserNameDoesNotExist") == 0)
186 {
Jiaqing Zhaod8a5d5d2022-08-05 16:21:51 +0800187 messages::resourceNotFound(asyncResp->res, "ManagerAccount", username);
jayaprakash Mutyala66b5ca72019-08-07 20:26:37 +0000188 }
Ed Tanousd4d25792020-09-29 15:15:03 -0700189 else if ((strcmp(errorMessage,
190 "xyz.openbmc_project.Common.Error.InvalidArgument") ==
191 0) ||
George Liu0fda0f12021-11-16 10:06:17 +0800192 (strcmp(
193 errorMessage,
194 "xyz.openbmc_project.User.Common.Error.UserNameGroupFail") ==
195 0))
jayaprakash Mutyala66b5ca72019-08-07 20:26:37 +0000196 {
197 messages::propertyValueFormatError(asyncResp->res, newUser, "UserName");
198 }
199 else if (strcmp(errorMessage,
200 "xyz.openbmc_project.User.Common.Error.NoResource") == 0)
201 {
202 messages::createLimitReachedForResource(asyncResp->res);
203 }
jayaprakash Mutyala66b5ca72019-08-07 20:26:37 +0000204 else
205 {
206 messages::internalError(asyncResp->res);
207 }
jayaprakash Mutyala66b5ca72019-08-07 20:26:37 +0000208}
209
Ed Tanous81ce6092020-12-17 16:54:55 +0000210inline void parseLDAPConfigData(nlohmann::json& jsonResponse,
Ed Tanous23a21a12020-07-25 04:45:05 +0000211 const LDAPConfigData& confData,
212 const std::string& ldapType)
Ratan Gupta6973a582018-12-13 18:25:44 +0530213{
Ratan Guptaab828d72019-04-22 14:18:33 +0530214 std::string service =
215 (ldapType == "LDAP") ? "LDAPService" : "ActiveDirectoryService";
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600216
Ed Tanous14766872022-03-15 10:44:42 -0700217 nlohmann::json& ldap = jsonResponse[ldapType];
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600218
Ed Tanous14766872022-03-15 10:44:42 -0700219 ldap["ServiceEnabled"] = confData.serviceEnabled;
220 ldap["ServiceAddresses"] = nlohmann::json::array({confData.uri});
221 ldap["Authentication"]["AuthenticationType"] = "UsernameAndPassword";
222 ldap["Authentication"]["Username"] = confData.bindDN;
223 ldap["Authentication"]["Password"] = nullptr;
224
225 ldap["LDAPService"]["SearchSettings"]["BaseDistinguishedNames"] =
226 nlohmann::json::array({confData.baseDN});
227 ldap["LDAPService"]["SearchSettings"]["UsernameAttribute"] =
228 confData.userNameAttribute;
229 ldap["LDAPService"]["SearchSettings"]["GroupsAttribute"] =
230 confData.groupAttribute;
231
232 nlohmann::json& roleMapArray = ldap["RemoteRoleMapping"];
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600233 roleMapArray = nlohmann::json::array();
Ed Tanous9eb808c2022-01-25 10:19:23 -0800234 for (const auto& obj : confData.groupRoleList)
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600235 {
236 BMCWEB_LOG_DEBUG << "Pushing the data groupName="
237 << obj.second.groupName << "\n";
Ed Tanous613dabe2022-07-09 11:17:36 -0700238
239 nlohmann::json::array_t remoteGroupArray;
240 nlohmann::json::object_t remoteGroup;
241 remoteGroup["RemoteGroup"] = obj.second.groupName;
242 remoteGroupArray.emplace_back(std::move(remoteGroup));
243 roleMapArray.emplace_back(std::move(remoteGroupArray));
244
245 nlohmann::json::array_t localRoleArray;
246 nlohmann::json::object_t localRole;
247 localRole["LocalRole"] = getRoleIdFromPrivilege(obj.second.privilege);
248 localRoleArray.emplace_back(std::move(localRole));
249 roleMapArray.emplace_back(std::move(localRoleArray));
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600250 }
Ratan Gupta6973a582018-12-13 18:25:44 +0530251}
252
253/**
Ratan Gupta06785242019-07-26 22:30:16 +0530254 * @brief validates given JSON input and then calls appropriate method to
255 * create, to delete or to set Rolemapping object based on the given input.
256 *
257 */
Ed Tanous23a21a12020-07-25 04:45:05 +0000258inline void handleRoleMapPatch(
zhanghch058d1b46d2021-04-01 11:18:24 +0800259 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ratan Gupta06785242019-07-26 22:30:16 +0530260 const std::vector<std::pair<std::string, LDAPRoleMapData>>& roleMapObjData,
Ed Tanousf23b7292020-10-15 09:41:17 -0700261 const std::string& serverType, const std::vector<nlohmann::json>& input)
Ratan Gupta06785242019-07-26 22:30:16 +0530262{
263 for (size_t index = 0; index < input.size(); index++)
264 {
Ed Tanousf23b7292020-10-15 09:41:17 -0700265 const nlohmann::json& thisJson = input[index];
Ratan Gupta06785242019-07-26 22:30:16 +0530266
267 if (thisJson.is_null())
268 {
269 // delete the existing object
270 if (index < roleMapObjData.size())
271 {
272 crow::connections::systemBus->async_method_call(
273 [asyncResp, roleMapObjData, serverType,
274 index](const boost::system::error_code ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700275 if (ec)
276 {
277 BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
278 messages::internalError(asyncResp->res);
279 return;
280 }
281 asyncResp->res
282 .jsonValue[serverType]["RemoteRoleMapping"][index] =
283 nullptr;
Ratan Gupta06785242019-07-26 22:30:16 +0530284 },
285 ldapDbusService, roleMapObjData[index].first,
286 "xyz.openbmc_project.Object.Delete", "Delete");
287 }
288 else
289 {
290 BMCWEB_LOG_ERROR << "Can't delete the object";
291 messages::propertyValueTypeError(
Ed Tanous71f52d92021-02-19 08:51:17 -0800292 asyncResp->res,
293 thisJson.dump(2, ' ', true,
294 nlohmann::json::error_handler_t::replace),
Ratan Gupta06785242019-07-26 22:30:16 +0530295 "RemoteRoleMapping/" + std::to_string(index));
296 return;
297 }
298 }
299 else if (thisJson.empty())
300 {
301 // Don't do anything for the empty objects,parse next json
302 // eg {"RemoteRoleMapping",[{}]}
303 }
304 else
305 {
306 // update/create the object
307 std::optional<std::string> remoteGroup;
308 std::optional<std::string> localRole;
309
Ed Tanousf23b7292020-10-15 09:41:17 -0700310 // This is a copy, but it's required in this case because of how
311 // readJson is structured
312 nlohmann::json thisJsonCopy = thisJson;
313 if (!json_util::readJson(thisJsonCopy, asyncResp->res,
314 "RemoteGroup", remoteGroup, "LocalRole",
315 localRole))
Ratan Gupta06785242019-07-26 22:30:16 +0530316 {
317 continue;
318 }
319
320 // Update existing RoleMapping Object
321 if (index < roleMapObjData.size())
322 {
323 BMCWEB_LOG_DEBUG << "Update Role Map Object";
324 // If "RemoteGroup" info is provided
325 if (remoteGroup)
326 {
327 crow::connections::systemBus->async_method_call(
328 [asyncResp, roleMapObjData, serverType, index,
329 remoteGroup](const boost::system::error_code ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700330 if (ec)
331 {
332 BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
333 messages::internalError(asyncResp->res);
334 return;
335 }
336 asyncResp->res
337 .jsonValue[serverType]["RemoteRoleMapping"][index]
338 ["RemoteGroup"] = *remoteGroup;
Ratan Gupta06785242019-07-26 22:30:16 +0530339 },
340 ldapDbusService, roleMapObjData[index].first,
341 propertyInterface, "Set",
342 "xyz.openbmc_project.User.PrivilegeMapperEntry",
343 "GroupName",
Ed Tanous168e20c2021-12-13 14:39:53 -0800344 dbus::utility::DbusVariantType(
345 std::move(*remoteGroup)));
Ratan Gupta06785242019-07-26 22:30:16 +0530346 }
347
348 // If "LocalRole" info is provided
349 if (localRole)
350 {
351 crow::connections::systemBus->async_method_call(
352 [asyncResp, roleMapObjData, serverType, index,
353 localRole](const boost::system::error_code ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700354 if (ec)
355 {
356 BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
357 messages::internalError(asyncResp->res);
358 return;
359 }
360 asyncResp->res
361 .jsonValue[serverType]["RemoteRoleMapping"][index]
362 ["LocalRole"] = *localRole;
Ratan Gupta06785242019-07-26 22:30:16 +0530363 },
364 ldapDbusService, roleMapObjData[index].first,
365 propertyInterface, "Set",
366 "xyz.openbmc_project.User.PrivilegeMapperEntry",
367 "Privilege",
Ed Tanous168e20c2021-12-13 14:39:53 -0800368 dbus::utility::DbusVariantType(
Ratan Gupta06785242019-07-26 22:30:16 +0530369 getPrivilegeFromRoleId(std::move(*localRole))));
370 }
371 }
372 // Create a new RoleMapping Object.
373 else
374 {
375 BMCWEB_LOG_DEBUG
376 << "setRoleMappingProperties: Creating new Object";
377 std::string pathString =
378 "RemoteRoleMapping/" + std::to_string(index);
379
380 if (!localRole)
381 {
382 messages::propertyMissing(asyncResp->res,
383 pathString + "/LocalRole");
384 continue;
385 }
386 if (!remoteGroup)
387 {
388 messages::propertyMissing(asyncResp->res,
389 pathString + "/RemoteGroup");
390 continue;
391 }
392
393 std::string dbusObjectPath;
394 if (serverType == "ActiveDirectory")
395 {
Ed Tanous2c70f802020-09-28 14:29:23 -0700396 dbusObjectPath = adConfigObject;
Ratan Gupta06785242019-07-26 22:30:16 +0530397 }
398 else if (serverType == "LDAP")
399 {
Ed Tanous23a21a12020-07-25 04:45:05 +0000400 dbusObjectPath = ldapConfigObjectName;
Ratan Gupta06785242019-07-26 22:30:16 +0530401 }
402
403 BMCWEB_LOG_DEBUG << "Remote Group=" << *remoteGroup
404 << ",LocalRole=" << *localRole;
405
406 crow::connections::systemBus->async_method_call(
Ed Tanous271584a2019-07-09 16:24:22 -0700407 [asyncResp, serverType, localRole,
Ratan Gupta06785242019-07-26 22:30:16 +0530408 remoteGroup](const boost::system::error_code ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700409 if (ec)
410 {
411 BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
412 messages::internalError(asyncResp->res);
413 return;
414 }
415 nlohmann::json& remoteRoleJson =
416 asyncResp->res
417 .jsonValue[serverType]["RemoteRoleMapping"];
418 nlohmann::json::object_t roleMapEntry;
419 roleMapEntry["LocalRole"] = *localRole;
420 roleMapEntry["RemoteGroup"] = *remoteGroup;
421 remoteRoleJson.push_back(std::move(roleMapEntry));
Ratan Gupta06785242019-07-26 22:30:16 +0530422 },
423 ldapDbusService, dbusObjectPath, ldapPrivMapperInterface,
Ed Tanous3174e4d2020-10-07 11:41:22 -0700424 "Create", *remoteGroup,
Ratan Gupta06785242019-07-26 22:30:16 +0530425 getPrivilegeFromRoleId(std::move(*localRole)));
426 }
427 }
428 }
429}
430
431/**
Ratan Gupta6973a582018-12-13 18:25:44 +0530432 * Function that retrieves all properties for LDAP config object
433 * into JSON
434 */
435template <typename CallbackFunc>
436inline void getLDAPConfigData(const std::string& ldapType,
437 CallbackFunc&& callback)
438{
Ratan Guptaab828d72019-04-22 14:18:33 +0530439
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600440 const std::array<const char*, 2> interfaces = {ldapEnableInterface,
Ratan Gupta6973a582018-12-13 18:25:44 +0530441 ldapConfigInterface};
442
443 crow::connections::systemBus->async_method_call(
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600444 [callback, ldapType](const boost::system::error_code ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800445 const dbus::utility::MapperGetObject& resp) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700446 if (ec || resp.empty())
447 {
448 BMCWEB_LOG_ERROR
449 << "DBUS response error during getting of service name: " << ec;
450 LDAPConfigData empty{};
451 callback(false, empty, ldapType);
452 return;
453 }
454 std::string service = resp.begin()->first;
455 crow::connections::systemBus->async_method_call(
456 [callback,
457 ldapType](const boost::system::error_code errorCode,
458 const dbus::utility::ManagedObjectType& ldapObjects) {
459 LDAPConfigData confData{};
460 if (errorCode)
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600461 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700462 callback(false, confData, ldapType);
463 BMCWEB_LOG_ERROR << "D-Bus responses error: " << errorCode;
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600464 return;
465 }
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600466
Ed Tanous002d39b2022-05-31 08:59:27 -0700467 std::string ldapDbusType;
468 std::string searchString;
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600469
Ed Tanous002d39b2022-05-31 08:59:27 -0700470 if (ldapType == "LDAP")
471 {
472 ldapDbusType =
473 "xyz.openbmc_project.User.Ldap.Config.Type.OpenLdap";
474 searchString = "openldap";
475 }
476 else if (ldapType == "ActiveDirectory")
477 {
478 ldapDbusType =
479 "xyz.openbmc_project.User.Ldap.Config.Type.ActiveDirectory";
480 searchString = "active_directory";
481 }
482 else
483 {
484 BMCWEB_LOG_ERROR << "Can't get the DbusType for the given type="
485 << ldapType;
486 callback(false, confData, ldapType);
487 return;
488 }
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600489
Ed Tanous002d39b2022-05-31 08:59:27 -0700490 std::string ldapEnableInterfaceStr = ldapEnableInterface;
491 std::string ldapConfigInterfaceStr = ldapConfigInterface;
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600492
Ed Tanous002d39b2022-05-31 08:59:27 -0700493 for (const auto& object : ldapObjects)
494 {
495 // let's find the object whose ldap type is equal to the
496 // given type
497 if (object.first.str.find(searchString) == std::string::npos)
498 {
499 continue;
500 }
501
502 for (const auto& interface : object.second)
503 {
504 if (interface.first == ldapEnableInterfaceStr)
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600505 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700506 // rest of the properties are string.
507 for (const auto& property : interface.second)
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600508 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700509 if (property.first == "Enabled")
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600510 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700511 const bool* value =
512 std::get_if<bool>(&property.second);
513 if (value == nullptr)
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600514 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700515 continue;
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600516 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700517 confData.serviceEnabled = *value;
518 break;
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600519 }
520 }
521 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700522 else if (interface.first == ldapConfigInterfaceStr)
523 {
524
525 for (const auto& property : interface.second)
526 {
527 const std::string* strValue =
528 std::get_if<std::string>(&property.second);
529 if (strValue == nullptr)
530 {
531 continue;
532 }
533 if (property.first == "LDAPServerURI")
534 {
535 confData.uri = *strValue;
536 }
537 else if (property.first == "LDAPBindDN")
538 {
539 confData.bindDN = *strValue;
540 }
541 else if (property.first == "LDAPBaseDN")
542 {
543 confData.baseDN = *strValue;
544 }
545 else if (property.first == "LDAPSearchScope")
546 {
547 confData.searchScope = *strValue;
548 }
549 else if (property.first == "GroupNameAttribute")
550 {
551 confData.groupAttribute = *strValue;
552 }
553 else if (property.first == "UserNameAttribute")
554 {
555 confData.userNameAttribute = *strValue;
556 }
557 else if (property.first == "LDAPType")
558 {
559 confData.serverType = *strValue;
560 }
561 }
562 }
563 else if (interface.first ==
564 "xyz.openbmc_project.User.PrivilegeMapperEntry")
565 {
566 LDAPRoleMapData roleMapData{};
567 for (const auto& property : interface.second)
568 {
569 const std::string* strValue =
570 std::get_if<std::string>(&property.second);
571
572 if (strValue == nullptr)
573 {
574 continue;
575 }
576
577 if (property.first == "GroupName")
578 {
579 roleMapData.groupName = *strValue;
580 }
581 else if (property.first == "Privilege")
582 {
583 roleMapData.privilege = *strValue;
584 }
585 }
586
587 confData.groupRoleList.emplace_back(object.first.str,
588 roleMapData);
589 }
590 }
591 }
592 callback(true, confData, ldapType);
593 },
594 service, ldapRootObject, dbusObjManagerIntf, "GetManagedObjects");
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600595 },
596 mapperBusName, mapperObjectPath, mapperIntf, "GetObject",
Ed Tanous23a21a12020-07-25 04:45:05 +0000597 ldapConfigObjectName, interfaces);
Ratan Gupta6973a582018-12-13 18:25:44 +0530598}
599
Ed Tanous6c51eab2021-06-03 12:30:29 -0700600/**
601 * @brief parses the authentication section under the LDAP
602 * @param input JSON data
603 * @param asyncResp pointer to the JSON response
604 * @param userName userName to be filled from the given JSON.
605 * @param password password to be filled from the given JSON.
606 */
Ed Tanous4f48d5f2021-06-21 08:27:45 -0700607inline void parseLDAPAuthenticationJson(
Ed Tanous6c51eab2021-06-03 12:30:29 -0700608 nlohmann::json input, const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
609 std::optional<std::string>& username, std::optional<std::string>& password)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700610{
Ed Tanous6c51eab2021-06-03 12:30:29 -0700611 std::optional<std::string> authType;
612
613 if (!json_util::readJson(input, asyncResp->res, "AuthenticationType",
614 authType, "Username", username, "Password",
615 password))
Ed Tanous1abe55e2018-09-05 08:30:59 -0700616 {
Ed Tanous6c51eab2021-06-03 12:30:29 -0700617 return;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700618 }
Ed Tanous6c51eab2021-06-03 12:30:29 -0700619 if (!authType)
Ratan Gupta8a07d282019-03-16 08:33:47 +0530620 {
Ed Tanous6c51eab2021-06-03 12:30:29 -0700621 return;
Ratan Gupta8a07d282019-03-16 08:33:47 +0530622 }
Ed Tanous6c51eab2021-06-03 12:30:29 -0700623 if (*authType != "UsernameAndPassword")
Ratan Gupta8a07d282019-03-16 08:33:47 +0530624 {
Ed Tanous6c51eab2021-06-03 12:30:29 -0700625 messages::propertyValueNotInList(asyncResp->res, *authType,
626 "AuthenticationType");
627 return;
Ratan Gupta8a07d282019-03-16 08:33:47 +0530628 }
Ed Tanous6c51eab2021-06-03 12:30:29 -0700629}
630/**
631 * @brief parses the LDAPService section under the LDAP
632 * @param input JSON data
633 * @param asyncResp pointer to the JSON response
634 * @param baseDNList baseDN to be filled from the given JSON.
635 * @param userNameAttribute userName to be filled from the given JSON.
636 * @param groupaAttribute password to be filled from the given JSON.
637 */
Ratan Gupta8a07d282019-03-16 08:33:47 +0530638
Ed Tanous4f48d5f2021-06-21 08:27:45 -0700639inline void
640 parseLDAPServiceJson(nlohmann::json input,
641 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
642 std::optional<std::vector<std::string>>& baseDNList,
643 std::optional<std::string>& userNameAttribute,
644 std::optional<std::string>& groupsAttribute)
Ed Tanous6c51eab2021-06-03 12:30:29 -0700645{
646 std::optional<nlohmann::json> searchSettings;
647
648 if (!json_util::readJson(input, asyncResp->res, "SearchSettings",
649 searchSettings))
Ratan Gupta8a07d282019-03-16 08:33:47 +0530650 {
Ed Tanous6c51eab2021-06-03 12:30:29 -0700651 return;
Ratan Gupta8a07d282019-03-16 08:33:47 +0530652 }
Ed Tanous6c51eab2021-06-03 12:30:29 -0700653 if (!searchSettings)
Ratan Gupta8a07d282019-03-16 08:33:47 +0530654 {
Ed Tanous6c51eab2021-06-03 12:30:29 -0700655 return;
Ratan Gupta8a07d282019-03-16 08:33:47 +0530656 }
Ed Tanous6c51eab2021-06-03 12:30:29 -0700657 if (!json_util::readJson(*searchSettings, asyncResp->res,
658 "BaseDistinguishedNames", baseDNList,
659 "UsernameAttribute", userNameAttribute,
660 "GroupsAttribute", groupsAttribute))
Ratan Gupta8a07d282019-03-16 08:33:47 +0530661 {
Ed Tanous6c51eab2021-06-03 12:30:29 -0700662 return;
Ratan Gupta8a07d282019-03-16 08:33:47 +0530663 }
Ed Tanous6c51eab2021-06-03 12:30:29 -0700664}
665/**
666 * @brief updates the LDAP server address and updates the
667 json response with the new value.
668 * @param serviceAddressList address to be updated.
669 * @param asyncResp pointer to the JSON response
670 * @param ldapServerElementName Type of LDAP
671 server(openLDAP/ActiveDirectory)
672 */
Ratan Gupta8a07d282019-03-16 08:33:47 +0530673
Ed Tanous4f48d5f2021-06-21 08:27:45 -0700674inline void handleServiceAddressPatch(
Ed Tanous6c51eab2021-06-03 12:30:29 -0700675 const std::vector<std::string>& serviceAddressList,
676 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
677 const std::string& ldapServerElementName,
678 const std::string& ldapConfigObject)
679{
680 crow::connections::systemBus->async_method_call(
681 [asyncResp, ldapServerElementName,
682 serviceAddressList](const boost::system::error_code ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700683 if (ec)
684 {
685 BMCWEB_LOG_DEBUG
686 << "Error Occurred in updating the service address";
687 messages::internalError(asyncResp->res);
688 return;
689 }
690 std::vector<std::string> modifiedserviceAddressList = {
691 serviceAddressList.front()};
692 asyncResp->res.jsonValue[ldapServerElementName]["ServiceAddresses"] =
693 modifiedserviceAddressList;
694 if ((serviceAddressList).size() > 1)
695 {
696 messages::propertyValueModified(asyncResp->res, "ServiceAddresses",
697 serviceAddressList.front());
698 }
699 BMCWEB_LOG_DEBUG << "Updated the service address";
Ed Tanous6c51eab2021-06-03 12:30:29 -0700700 },
701 ldapDbusService, ldapConfigObject, propertyInterface, "Set",
702 ldapConfigInterface, "LDAPServerURI",
Ed Tanous168e20c2021-12-13 14:39:53 -0800703 dbus::utility::DbusVariantType(serviceAddressList.front()));
Ed Tanous6c51eab2021-06-03 12:30:29 -0700704}
705/**
706 * @brief updates the LDAP Bind DN and updates the
707 json response with the new value.
708 * @param username name of the user which needs to be updated.
709 * @param asyncResp pointer to the JSON response
710 * @param ldapServerElementName Type of LDAP
711 server(openLDAP/ActiveDirectory)
712 */
Ratan Gupta8a07d282019-03-16 08:33:47 +0530713
Ed Tanous4f48d5f2021-06-21 08:27:45 -0700714inline void
715 handleUserNamePatch(const std::string& username,
716 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
717 const std::string& ldapServerElementName,
718 const std::string& ldapConfigObject)
Ed Tanous6c51eab2021-06-03 12:30:29 -0700719{
720 crow::connections::systemBus->async_method_call(
721 [asyncResp, username,
722 ldapServerElementName](const boost::system::error_code ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700723 if (ec)
724 {
725 BMCWEB_LOG_DEBUG << "Error occurred in updating the username";
726 messages::internalError(asyncResp->res);
727 return;
728 }
729 asyncResp->res
730 .jsonValue[ldapServerElementName]["Authentication"]["Username"] =
731 username;
732 BMCWEB_LOG_DEBUG << "Updated the username";
Ed Tanous6c51eab2021-06-03 12:30:29 -0700733 },
734 ldapDbusService, ldapConfigObject, propertyInterface, "Set",
Ed Tanous168e20c2021-12-13 14:39:53 -0800735 ldapConfigInterface, "LDAPBindDN",
736 dbus::utility::DbusVariantType(username));
Ed Tanous6c51eab2021-06-03 12:30:29 -0700737}
738
739/**
740 * @brief updates the LDAP password
741 * @param password : ldap password which needs to be updated.
742 * @param asyncResp pointer to the JSON response
743 * @param ldapServerElementName Type of LDAP
744 * server(openLDAP/ActiveDirectory)
745 */
746
Ed Tanous4f48d5f2021-06-21 08:27:45 -0700747inline void
748 handlePasswordPatch(const std::string& password,
749 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
750 const std::string& ldapServerElementName,
751 const std::string& ldapConfigObject)
Ed Tanous6c51eab2021-06-03 12:30:29 -0700752{
753 crow::connections::systemBus->async_method_call(
754 [asyncResp, password,
755 ldapServerElementName](const boost::system::error_code ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700756 if (ec)
757 {
758 BMCWEB_LOG_DEBUG << "Error occurred in updating the password";
759 messages::internalError(asyncResp->res);
760 return;
761 }
762 asyncResp->res
763 .jsonValue[ldapServerElementName]["Authentication"]["Password"] =
764 "";
765 BMCWEB_LOG_DEBUG << "Updated the password";
Ed Tanous6c51eab2021-06-03 12:30:29 -0700766 },
767 ldapDbusService, ldapConfigObject, propertyInterface, "Set",
768 ldapConfigInterface, "LDAPBindDNPassword",
Ed Tanous168e20c2021-12-13 14:39:53 -0800769 dbus::utility::DbusVariantType(password));
Ed Tanous6c51eab2021-06-03 12:30:29 -0700770}
771
772/**
773 * @brief updates the LDAP BaseDN and updates the
774 json response with the new value.
775 * @param baseDNList baseDN list which needs to be updated.
776 * @param asyncResp pointer to the JSON response
777 * @param ldapServerElementName Type of LDAP
778 server(openLDAP/ActiveDirectory)
779 */
780
Ed Tanous4f48d5f2021-06-21 08:27:45 -0700781inline void
782 handleBaseDNPatch(const std::vector<std::string>& baseDNList,
783 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
784 const std::string& ldapServerElementName,
785 const std::string& ldapConfigObject)
Ed Tanous6c51eab2021-06-03 12:30:29 -0700786{
787 crow::connections::systemBus->async_method_call(
788 [asyncResp, baseDNList,
789 ldapServerElementName](const boost::system::error_code ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700790 if (ec)
791 {
792 BMCWEB_LOG_DEBUG << "Error Occurred in Updating the base DN";
793 messages::internalError(asyncResp->res);
794 return;
795 }
796 auto& serverTypeJson = asyncResp->res.jsonValue[ldapServerElementName];
797 auto& searchSettingsJson =
798 serverTypeJson["LDAPService"]["SearchSettings"];
799 std::vector<std::string> modifiedBaseDNList = {baseDNList.front()};
800 searchSettingsJson["BaseDistinguishedNames"] = modifiedBaseDNList;
801 if (baseDNList.size() > 1)
802 {
803 messages::propertyValueModified(
804 asyncResp->res, "BaseDistinguishedNames", baseDNList.front());
805 }
806 BMCWEB_LOG_DEBUG << "Updated the base DN";
Ed Tanous6c51eab2021-06-03 12:30:29 -0700807 },
808 ldapDbusService, ldapConfigObject, propertyInterface, "Set",
809 ldapConfigInterface, "LDAPBaseDN",
Ed Tanous168e20c2021-12-13 14:39:53 -0800810 dbus::utility::DbusVariantType(baseDNList.front()));
Ed Tanous6c51eab2021-06-03 12:30:29 -0700811}
812/**
813 * @brief updates the LDAP user name attribute and updates the
814 json response with the new value.
815 * @param userNameAttribute attribute to be updated.
816 * @param asyncResp pointer to the JSON response
817 * @param ldapServerElementName Type of LDAP
818 server(openLDAP/ActiveDirectory)
819 */
820
Ed Tanous4f48d5f2021-06-21 08:27:45 -0700821inline void
822 handleUserNameAttrPatch(const std::string& userNameAttribute,
823 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
824 const std::string& ldapServerElementName,
825 const std::string& ldapConfigObject)
Ed Tanous6c51eab2021-06-03 12:30:29 -0700826{
827 crow::connections::systemBus->async_method_call(
828 [asyncResp, userNameAttribute,
829 ldapServerElementName](const boost::system::error_code ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700830 if (ec)
831 {
832 BMCWEB_LOG_DEBUG << "Error Occurred in Updating the "
833 "username attribute";
834 messages::internalError(asyncResp->res);
835 return;
836 }
837 auto& serverTypeJson = asyncResp->res.jsonValue[ldapServerElementName];
838 auto& searchSettingsJson =
839 serverTypeJson["LDAPService"]["SearchSettings"];
840 searchSettingsJson["UsernameAttribute"] = userNameAttribute;
841 BMCWEB_LOG_DEBUG << "Updated the user name attr.";
Ed Tanous6c51eab2021-06-03 12:30:29 -0700842 },
843 ldapDbusService, ldapConfigObject, propertyInterface, "Set",
844 ldapConfigInterface, "UserNameAttribute",
Ed Tanous168e20c2021-12-13 14:39:53 -0800845 dbus::utility::DbusVariantType(userNameAttribute));
Ed Tanous6c51eab2021-06-03 12:30:29 -0700846}
847/**
848 * @brief updates the LDAP group attribute and updates the
849 json response with the new value.
850 * @param groupsAttribute attribute to be updated.
851 * @param asyncResp pointer to the JSON response
852 * @param ldapServerElementName Type of LDAP
853 server(openLDAP/ActiveDirectory)
854 */
855
Ed Tanous4f48d5f2021-06-21 08:27:45 -0700856inline void handleGroupNameAttrPatch(
Ed Tanous6c51eab2021-06-03 12:30:29 -0700857 const std::string& groupsAttribute,
858 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
859 const std::string& ldapServerElementName,
860 const std::string& ldapConfigObject)
861{
862 crow::connections::systemBus->async_method_call(
863 [asyncResp, groupsAttribute,
864 ldapServerElementName](const boost::system::error_code ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700865 if (ec)
866 {
867 BMCWEB_LOG_DEBUG << "Error Occurred in Updating the "
868 "groupname attribute";
869 messages::internalError(asyncResp->res);
870 return;
871 }
872 auto& serverTypeJson = asyncResp->res.jsonValue[ldapServerElementName];
873 auto& searchSettingsJson =
874 serverTypeJson["LDAPService"]["SearchSettings"];
875 searchSettingsJson["GroupsAttribute"] = groupsAttribute;
876 BMCWEB_LOG_DEBUG << "Updated the groupname attr";
Ed Tanous6c51eab2021-06-03 12:30:29 -0700877 },
878 ldapDbusService, ldapConfigObject, propertyInterface, "Set",
879 ldapConfigInterface, "GroupNameAttribute",
Ed Tanous168e20c2021-12-13 14:39:53 -0800880 dbus::utility::DbusVariantType(groupsAttribute));
Ed Tanous6c51eab2021-06-03 12:30:29 -0700881}
882/**
883 * @brief updates the LDAP service enable and updates the
884 json response with the new value.
885 * @param input JSON data.
886 * @param asyncResp pointer to the JSON response
887 * @param ldapServerElementName Type of LDAP
888 server(openLDAP/ActiveDirectory)
889 */
890
Ed Tanous4f48d5f2021-06-21 08:27:45 -0700891inline void handleServiceEnablePatch(
Ed Tanous6c51eab2021-06-03 12:30:29 -0700892 bool serviceEnabled, const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
893 const std::string& ldapServerElementName,
894 const std::string& ldapConfigObject)
895{
896 crow::connections::systemBus->async_method_call(
897 [asyncResp, serviceEnabled,
898 ldapServerElementName](const boost::system::error_code ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700899 if (ec)
900 {
901 BMCWEB_LOG_DEBUG << "Error Occurred in Updating the service enable";
902 messages::internalError(asyncResp->res);
903 return;
904 }
905 asyncResp->res.jsonValue[ldapServerElementName]["ServiceEnabled"] =
906 serviceEnabled;
907 BMCWEB_LOG_DEBUG << "Updated Service enable = " << serviceEnabled;
Ed Tanous6c51eab2021-06-03 12:30:29 -0700908 },
909 ldapDbusService, ldapConfigObject, propertyInterface, "Set",
Ed Tanous168e20c2021-12-13 14:39:53 -0800910 ldapEnableInterface, "Enabled",
911 dbus::utility::DbusVariantType(serviceEnabled));
Ed Tanous6c51eab2021-06-03 12:30:29 -0700912}
913
Ed Tanous4f48d5f2021-06-21 08:27:45 -0700914inline void
915 handleAuthMethodsPatch(nlohmann::json& input,
916 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Ed Tanous6c51eab2021-06-03 12:30:29 -0700917{
918 std::optional<bool> basicAuth;
919 std::optional<bool> cookie;
920 std::optional<bool> sessionToken;
921 std::optional<bool> xToken;
922 std::optional<bool> tls;
923
924 if (!json_util::readJson(input, asyncResp->res, "BasicAuth", basicAuth,
925 "Cookie", cookie, "SessionToken", sessionToken,
926 "XToken", xToken, "TLS", tls))
Ratan Gupta8a07d282019-03-16 08:33:47 +0530927 {
Ed Tanous6c51eab2021-06-03 12:30:29 -0700928 BMCWEB_LOG_ERROR << "Cannot read values from AuthMethod tag";
929 return;
930 }
931
932 // Make a copy of methods configuration
933 persistent_data::AuthConfigMethods authMethodsConfig =
934 persistent_data::SessionStore::getInstance().getAuthMethodsConfig();
935
936 if (basicAuth)
937 {
938#ifndef BMCWEB_ENABLE_BASIC_AUTHENTICATION
939 messages::actionNotSupported(
George Liu0fda0f12021-11-16 10:06:17 +0800940 asyncResp->res,
941 "Setting BasicAuth when basic-auth feature is disabled");
Ed Tanous6c51eab2021-06-03 12:30:29 -0700942 return;
943#endif
944 authMethodsConfig.basic = *basicAuth;
945 }
946
947 if (cookie)
948 {
949#ifndef BMCWEB_ENABLE_COOKIE_AUTHENTICATION
George Liu0fda0f12021-11-16 10:06:17 +0800950 messages::actionNotSupported(
951 asyncResp->res,
952 "Setting Cookie when cookie-auth feature is disabled");
Ed Tanous6c51eab2021-06-03 12:30:29 -0700953 return;
954#endif
955 authMethodsConfig.cookie = *cookie;
956 }
957
958 if (sessionToken)
959 {
960#ifndef BMCWEB_ENABLE_SESSION_AUTHENTICATION
961 messages::actionNotSupported(
George Liu0fda0f12021-11-16 10:06:17 +0800962 asyncResp->res,
963 "Setting SessionToken when session-auth feature is disabled");
Ed Tanous6c51eab2021-06-03 12:30:29 -0700964 return;
965#endif
966 authMethodsConfig.sessionToken = *sessionToken;
967 }
968
969 if (xToken)
970 {
971#ifndef BMCWEB_ENABLE_XTOKEN_AUTHENTICATION
George Liu0fda0f12021-11-16 10:06:17 +0800972 messages::actionNotSupported(
973 asyncResp->res,
974 "Setting XToken when xtoken-auth feature is disabled");
Ed Tanous6c51eab2021-06-03 12:30:29 -0700975 return;
976#endif
977 authMethodsConfig.xtoken = *xToken;
978 }
979
980 if (tls)
981 {
982#ifndef BMCWEB_ENABLE_MUTUAL_TLS_AUTHENTICATION
George Liu0fda0f12021-11-16 10:06:17 +0800983 messages::actionNotSupported(
984 asyncResp->res,
985 "Setting TLS when mutual-tls-auth feature is disabled");
Ed Tanous6c51eab2021-06-03 12:30:29 -0700986 return;
987#endif
988 authMethodsConfig.tls = *tls;
989 }
990
991 if (!authMethodsConfig.basic && !authMethodsConfig.cookie &&
992 !authMethodsConfig.sessionToken && !authMethodsConfig.xtoken &&
993 !authMethodsConfig.tls)
994 {
995 // Do not allow user to disable everything
996 messages::actionNotSupported(asyncResp->res,
997 "of disabling all available methods");
998 return;
999 }
1000
1001 persistent_data::SessionStore::getInstance().updateAuthMethodsConfig(
1002 authMethodsConfig);
1003 // Save configuration immediately
1004 persistent_data::getConfig().writeData();
1005
1006 messages::success(asyncResp->res);
1007}
1008
1009/**
1010 * @brief Get the required values from the given JSON, validates the
1011 * value and create the LDAP config object.
1012 * @param input JSON data
1013 * @param asyncResp pointer to the JSON response
1014 * @param serverType Type of LDAP server(openLDAP/ActiveDirectory)
1015 */
1016
1017inline void handleLDAPPatch(nlohmann::json& input,
1018 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1019 const std::string& serverType)
1020{
1021 std::string dbusObjectPath;
1022 if (serverType == "ActiveDirectory")
1023 {
1024 dbusObjectPath = adConfigObject;
1025 }
1026 else if (serverType == "LDAP")
1027 {
1028 dbusObjectPath = ldapConfigObjectName;
1029 }
1030 else
1031 {
1032 return;
1033 }
1034
1035 std::optional<nlohmann::json> authentication;
1036 std::optional<nlohmann::json> ldapService;
1037 std::optional<std::vector<std::string>> serviceAddressList;
1038 std::optional<bool> serviceEnabled;
1039 std::optional<std::vector<std::string>> baseDNList;
1040 std::optional<std::string> userNameAttribute;
1041 std::optional<std::string> groupsAttribute;
1042 std::optional<std::string> userName;
1043 std::optional<std::string> password;
1044 std::optional<std::vector<nlohmann::json>> remoteRoleMapData;
1045
1046 if (!json_util::readJson(input, asyncResp->res, "Authentication",
1047 authentication, "LDAPService", ldapService,
1048 "ServiceAddresses", serviceAddressList,
1049 "ServiceEnabled", serviceEnabled,
1050 "RemoteRoleMapping", remoteRoleMapData))
1051 {
1052 return;
1053 }
1054
1055 if (authentication)
1056 {
1057 parseLDAPAuthenticationJson(*authentication, asyncResp, userName,
1058 password);
1059 }
1060 if (ldapService)
1061 {
1062 parseLDAPServiceJson(*ldapService, asyncResp, baseDNList,
1063 userNameAttribute, groupsAttribute);
1064 }
1065 if (serviceAddressList)
1066 {
Ed Tanous26f69762022-01-25 09:49:11 -08001067 if (serviceAddressList->empty())
Ratan Guptaeb2bbe52019-04-22 14:27:01 +05301068 {
Ed Tanous6c51eab2021-06-03 12:30:29 -07001069 messages::propertyValueNotInList(asyncResp->res, "[]",
1070 "ServiceAddress");
Ed Tanouscb13a392020-07-25 19:02:03 +00001071 return;
1072 }
Ed Tanous6c51eab2021-06-03 12:30:29 -07001073 }
1074 if (baseDNList)
1075 {
Ed Tanous26f69762022-01-25 09:49:11 -08001076 if (baseDNList->empty())
Ratan Gupta8a07d282019-03-16 08:33:47 +05301077 {
Ed Tanous6c51eab2021-06-03 12:30:29 -07001078 messages::propertyValueNotInList(asyncResp->res, "[]",
1079 "BaseDistinguishedNames");
Ratan Gupta8a07d282019-03-16 08:33:47 +05301080 return;
1081 }
Ed Tanous6c51eab2021-06-03 12:30:29 -07001082 }
Ratan Gupta8a07d282019-03-16 08:33:47 +05301083
Ed Tanous6c51eab2021-06-03 12:30:29 -07001084 // nothing to update, then return
1085 if (!userName && !password && !serviceAddressList && !baseDNList &&
1086 !userNameAttribute && !groupsAttribute && !serviceEnabled &&
1087 !remoteRoleMapData)
1088 {
1089 return;
1090 }
1091
1092 // Get the existing resource first then keep modifying
1093 // whenever any property gets updated.
Ed Tanous002d39b2022-05-31 08:59:27 -07001094 getLDAPConfigData(
1095 serverType,
1096 [asyncResp, userName, password, baseDNList, userNameAttribute,
1097 groupsAttribute, serviceAddressList, serviceEnabled, dbusObjectPath,
1098 remoteRoleMapData](bool success, const LDAPConfigData& confData,
1099 const std::string& serverT) {
Ed Tanous6c51eab2021-06-03 12:30:29 -07001100 if (!success)
Ratan Gupta8a07d282019-03-16 08:33:47 +05301101 {
Ed Tanous6c51eab2021-06-03 12:30:29 -07001102 messages::internalError(asyncResp->res);
1103 return;
Ratan Gupta8a07d282019-03-16 08:33:47 +05301104 }
Ed Tanous6c51eab2021-06-03 12:30:29 -07001105 parseLDAPConfigData(asyncResp->res.jsonValue, confData, serverT);
1106 if (confData.serviceEnabled)
Ratan Gupta8a07d282019-03-16 08:33:47 +05301107 {
Ed Tanous6c51eab2021-06-03 12:30:29 -07001108 // Disable the service first and update the rest of
1109 // the properties.
1110 handleServiceEnablePatch(false, asyncResp, serverT, dbusObjectPath);
Ratan Gupta8a07d282019-03-16 08:33:47 +05301111 }
Ed Tanous6c51eab2021-06-03 12:30:29 -07001112
Ratan Gupta8a07d282019-03-16 08:33:47 +05301113 if (serviceAddressList)
1114 {
Ed Tanous6c51eab2021-06-03 12:30:29 -07001115 handleServiceAddressPatch(*serviceAddressList, asyncResp, serverT,
1116 dbusObjectPath);
Ratan Gupta8a07d282019-03-16 08:33:47 +05301117 }
Ed Tanous6c51eab2021-06-03 12:30:29 -07001118 if (userName)
1119 {
1120 handleUserNamePatch(*userName, asyncResp, serverT, dbusObjectPath);
1121 }
1122 if (password)
1123 {
1124 handlePasswordPatch(*password, asyncResp, serverT, dbusObjectPath);
1125 }
1126
Ratan Gupta8a07d282019-03-16 08:33:47 +05301127 if (baseDNList)
1128 {
Ed Tanous6c51eab2021-06-03 12:30:29 -07001129 handleBaseDNPatch(*baseDNList, asyncResp, serverT, dbusObjectPath);
1130 }
1131 if (userNameAttribute)
1132 {
1133 handleUserNameAttrPatch(*userNameAttribute, asyncResp, serverT,
1134 dbusObjectPath);
1135 }
1136 if (groupsAttribute)
1137 {
1138 handleGroupNameAttrPatch(*groupsAttribute, asyncResp, serverT,
1139 dbusObjectPath);
1140 }
1141 if (serviceEnabled)
1142 {
1143 // if user has given the value as true then enable
1144 // the service. if user has given false then no-op
1145 // as service is already stopped.
1146 if (*serviceEnabled)
Ratan Gupta8a07d282019-03-16 08:33:47 +05301147 {
Ed Tanous6c51eab2021-06-03 12:30:29 -07001148 handleServiceEnablePatch(*serviceEnabled, asyncResp, serverT,
1149 dbusObjectPath);
Ratan Gupta8a07d282019-03-16 08:33:47 +05301150 }
1151 }
jayaprakash Mutyala96200602020-04-08 11:09:10 +00001152 else
1153 {
Ed Tanous6c51eab2021-06-03 12:30:29 -07001154 // if user has not given the service enabled value
1155 // then revert it to the same state as it was
1156 // before.
1157 handleServiceEnablePatch(confData.serviceEnabled, asyncResp,
1158 serverT, dbusObjectPath);
jayaprakash Mutyala96200602020-04-08 11:09:10 +00001159 }
Ed Tanous04ae99e2018-09-20 15:54:36 -07001160
Ed Tanous6c51eab2021-06-03 12:30:29 -07001161 if (remoteRoleMapData)
1162 {
1163 handleRoleMapPatch(asyncResp, confData.groupRoleList, serverT,
1164 *remoteRoleMapData);
1165 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001166 });
Ed Tanous6c51eab2021-06-03 12:30:29 -07001167}
1168
1169inline void updateUserProperties(std::shared_ptr<bmcweb::AsyncResp> asyncResp,
1170 const std::string& username,
1171 std::optional<std::string> password,
1172 std::optional<bool> enabled,
1173 std::optional<std::string> roleId,
1174 std::optional<bool> locked)
1175{
P Dheeraj Srujan Kumarb477fd42021-12-16 07:17:51 +05301176 sdbusplus::message::object_path tempObjPath(rootUserDbusPath);
1177 tempObjPath /= username;
1178 std::string dbusObjectPath(tempObjPath);
Ed Tanous6c51eab2021-06-03 12:30:29 -07001179
1180 dbus::utility::checkDbusPathExists(
1181 dbusObjectPath,
Ed Tanous11063332021-09-24 11:55:44 -07001182 [dbusObjectPath, username, password(std::move(password)),
1183 roleId(std::move(roleId)), enabled, locked,
1184 asyncResp{std::move(asyncResp)}](int rc) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001185 if (rc <= 0)
1186 {
Jiaqing Zhaod8a5d5d2022-08-05 16:21:51 +08001187 messages::resourceNotFound(asyncResp->res, "ManagerAccount",
Ed Tanous002d39b2022-05-31 08:59:27 -07001188 username);
1189 return;
1190 }
1191
1192 if (password)
1193 {
1194 int retval = pamUpdatePassword(username, *password);
1195
1196 if (retval == PAM_USER_UNKNOWN)
Ed Tanous6c51eab2021-06-03 12:30:29 -07001197 {
Jiaqing Zhaod8a5d5d2022-08-05 16:21:51 +08001198 messages::resourceNotFound(asyncResp->res, "ManagerAccount",
1199 username);
Ed Tanous002d39b2022-05-31 08:59:27 -07001200 }
1201 else if (retval == PAM_AUTHTOK_ERR)
1202 {
1203 // If password is invalid
1204 messages::propertyValueFormatError(asyncResp->res, *password,
1205 "Password");
1206 BMCWEB_LOG_ERROR << "pamUpdatePassword Failed";
1207 }
1208 else if (retval != PAM_SUCCESS)
1209 {
1210 messages::internalError(asyncResp->res);
Ed Tanous6c51eab2021-06-03 12:30:29 -07001211 return;
1212 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001213 else
Ed Tanous6c51eab2021-06-03 12:30:29 -07001214 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001215 messages::success(asyncResp->res);
1216 }
1217 }
Ed Tanous6c51eab2021-06-03 12:30:29 -07001218
Ed Tanous002d39b2022-05-31 08:59:27 -07001219 if (enabled)
1220 {
1221 crow::connections::systemBus->async_method_call(
1222 [asyncResp](const boost::system::error_code ec) {
1223 if (ec)
Ed Tanous04ae99e2018-09-20 15:54:36 -07001224 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001225 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
Ayushi Smriti599c71d2019-08-23 17:43:18 +00001226 messages::internalError(asyncResp->res);
Ed Tanous04ae99e2018-09-20 15:54:36 -07001227 return;
1228 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001229 messages::success(asyncResp->res);
1230 return;
1231 },
1232 "xyz.openbmc_project.User.Manager", dbusObjectPath,
1233 "org.freedesktop.DBus.Properties", "Set",
1234 "xyz.openbmc_project.User.Attributes", "UserEnabled",
1235 dbus::utility::DbusVariantType{*enabled});
1236 }
1237
1238 if (roleId)
1239 {
1240 std::string priv = getPrivilegeFromRoleId(*roleId);
1241 if (priv.empty())
1242 {
1243 messages::propertyValueNotInList(asyncResp->res, *roleId,
1244 "RoleId");
1245 return;
1246 }
1247 if (priv == "priv-noaccess")
1248 {
1249 priv = "";
Ed Tanous6c51eab2021-06-03 12:30:29 -07001250 }
Ed Tanous04ae99e2018-09-20 15:54:36 -07001251
Ed Tanous002d39b2022-05-31 08:59:27 -07001252 crow::connections::systemBus->async_method_call(
1253 [asyncResp](const boost::system::error_code ec) {
1254 if (ec)
Ed Tanous04ae99e2018-09-20 15:54:36 -07001255 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001256 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
1257 messages::internalError(asyncResp->res);
Ed Tanous6c51eab2021-06-03 12:30:29 -07001258 return;
1259 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001260 messages::success(asyncResp->res);
1261 },
1262 "xyz.openbmc_project.User.Manager", dbusObjectPath,
1263 "org.freedesktop.DBus.Properties", "Set",
1264 "xyz.openbmc_project.User.Attributes", "UserPrivilege",
1265 dbus::utility::DbusVariantType{priv});
1266 }
Ed Tanous6c51eab2021-06-03 12:30:29 -07001267
Ed Tanous002d39b2022-05-31 08:59:27 -07001268 if (locked)
1269 {
1270 // admin can unlock the account which is locked by
1271 // successive authentication failures but admin should
1272 // not be allowed to lock an account.
1273 if (*locked)
1274 {
1275 messages::propertyValueNotInList(asyncResp->res, "true",
1276 "Locked");
1277 return;
Ed Tanous6c51eab2021-06-03 12:30:29 -07001278 }
1279
Ed Tanous002d39b2022-05-31 08:59:27 -07001280 crow::connections::systemBus->async_method_call(
1281 [asyncResp](const boost::system::error_code ec) {
1282 if (ec)
Ed Tanous6c51eab2021-06-03 12:30:29 -07001283 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001284 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
1285 messages::internalError(asyncResp->res);
Ed Tanous04ae99e2018-09-20 15:54:36 -07001286 return;
1287 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001288 messages::success(asyncResp->res);
1289 return;
1290 },
1291 "xyz.openbmc_project.User.Manager", dbusObjectPath,
1292 "org.freedesktop.DBus.Properties", "Set",
1293 "xyz.openbmc_project.User.Attributes",
1294 "UserLockedForFailedAttempt",
1295 dbus::utility::DbusVariantType{*locked});
1296 }
Ed Tanous6c51eab2021-06-03 12:30:29 -07001297 });
1298}
Ed Tanousb9b2e0b2018-09-13 13:47:50 -07001299
Ed Tanous4c7d4d32022-07-07 15:29:35 -07001300inline void handleAccountServiceHead(
1301 App& app, const crow::Request& req,
1302 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Ed Tanous1ef4c342022-05-12 16:12:36 -07001303{
Ed Tanous4c7d4d32022-07-07 15:29:35 -07001304
Ed Tanous1ef4c342022-05-12 16:12:36 -07001305 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1306 {
1307 return;
1308 }
Ed Tanous4c7d4d32022-07-07 15:29:35 -07001309 asyncResp->res.addHeader(
1310 boost::beast::http::field::link,
1311 "</redfish/v1/JsonSchemas/AccountService/AccountService.json>; rel=describedby");
1312}
1313
1314inline void
1315 handleAccountServiceGet(App& app, const crow::Request& req,
1316 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1317{
1318 handleAccountServiceHead(app, req, asyncResp);
Ed Tanous1ef4c342022-05-12 16:12:36 -07001319 const persistent_data::AuthConfigMethods& authMethodsConfig =
1320 persistent_data::SessionStore::getInstance().getAuthMethodsConfig();
1321
1322 nlohmann::json& json = asyncResp->res.jsonValue;
1323 json["@odata.id"] = "/redfish/v1/AccountService";
1324 json["@odata.type"] = "#AccountService."
1325 "v1_10_0.AccountService";
1326 json["Id"] = "AccountService";
1327 json["Name"] = "Account Service";
1328 json["Description"] = "Account Service";
1329 json["ServiceEnabled"] = true;
1330 json["MaxPasswordLength"] = 20;
1331 json["Accounts"]["@odata.id"] = "/redfish/v1/AccountService/Accounts";
1332 json["Roles"]["@odata.id"] = "/redfish/v1/AccountService/Roles";
1333 json["Oem"]["OpenBMC"]["@odata.type"] =
1334 "#OemAccountService.v1_0_0.AccountService";
1335 json["Oem"]["OpenBMC"]["@odata.id"] =
1336 "/redfish/v1/AccountService#/Oem/OpenBMC";
1337 json["Oem"]["OpenBMC"]["AuthMethods"]["BasicAuth"] =
1338 authMethodsConfig.basic;
1339 json["Oem"]["OpenBMC"]["AuthMethods"]["SessionToken"] =
1340 authMethodsConfig.sessionToken;
1341 json["Oem"]["OpenBMC"]["AuthMethods"]["XToken"] = authMethodsConfig.xtoken;
1342 json["Oem"]["OpenBMC"]["AuthMethods"]["Cookie"] = authMethodsConfig.cookie;
1343 json["Oem"]["OpenBMC"]["AuthMethods"]["TLS"] = authMethodsConfig.tls;
1344
1345 // /redfish/v1/AccountService/LDAP/Certificates is something only
1346 // ConfigureManager can access then only display when the user has
1347 // permissions ConfigureManager
1348 Privileges effectiveUserPrivileges =
1349 redfish::getUserPrivileges(req.userRole);
1350
1351 if (isOperationAllowedWithPrivileges({{"ConfigureManager"}},
1352 effectiveUserPrivileges))
1353 {
1354 asyncResp->res.jsonValue["LDAP"]["Certificates"]["@odata.id"] =
1355 "/redfish/v1/AccountService/LDAP/Certificates";
1356 }
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001357 sdbusplus::asio::getAllProperties(
1358 *crow::connections::systemBus, "xyz.openbmc_project.User.Manager",
1359 "/xyz/openbmc_project/user", "xyz.openbmc_project.User.AccountPolicy",
Ed Tanous1ef4c342022-05-12 16:12:36 -07001360 [asyncResp](const boost::system::error_code ec,
1361 const dbus::utility::DBusPropertiesMap& propertiesList) {
1362 if (ec)
1363 {
1364 messages::internalError(asyncResp->res);
1365 return;
1366 }
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001367
Ed Tanous1ef4c342022-05-12 16:12:36 -07001368 BMCWEB_LOG_DEBUG << "Got " << propertiesList.size()
1369 << "properties for AccountService";
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001370
1371 const uint8_t* minPasswordLength = nullptr;
1372 const uint32_t* accountUnlockTimeout = nullptr;
1373 const uint16_t* maxLoginAttemptBeforeLockout = nullptr;
1374
1375 const bool success = sdbusplus::unpackPropertiesNoThrow(
1376 dbus_utils::UnpackErrorPrinter(), propertiesList,
1377 "MinPasswordLength", minPasswordLength, "AccountUnlockTimeout",
1378 accountUnlockTimeout, "MaxLoginAttemptBeforeLockout",
1379 maxLoginAttemptBeforeLockout);
1380
1381 if (!success)
Ed Tanous1ef4c342022-05-12 16:12:36 -07001382 {
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001383 messages::internalError(asyncResp->res);
1384 return;
Ed Tanous1ef4c342022-05-12 16:12:36 -07001385 }
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001386
1387 if (minPasswordLength != nullptr)
1388 {
1389 asyncResp->res.jsonValue["MinPasswordLength"] = *minPasswordLength;
1390 }
1391
1392 if (accountUnlockTimeout != nullptr)
1393 {
1394 asyncResp->res.jsonValue["AccountLockoutDuration"] =
1395 *accountUnlockTimeout;
1396 }
1397
1398 if (maxLoginAttemptBeforeLockout != nullptr)
1399 {
1400 asyncResp->res.jsonValue["AccountLockoutThreshold"] =
1401 *maxLoginAttemptBeforeLockout;
1402 }
1403 });
Ed Tanous1ef4c342022-05-12 16:12:36 -07001404
Ed Tanous02cad962022-06-30 16:50:15 -07001405 auto callback = [asyncResp](bool success, const LDAPConfigData& confData,
Ed Tanous1ef4c342022-05-12 16:12:36 -07001406 const std::string& ldapType) {
1407 if (!success)
1408 {
1409 return;
1410 }
1411 parseLDAPConfigData(asyncResp->res.jsonValue, confData, ldapType);
1412 };
1413
1414 getLDAPConfigData("LDAP", callback);
1415 getLDAPConfigData("ActiveDirectory", callback);
1416}
1417
1418inline void handleAccountServicePatch(
1419 App& app, const crow::Request& req,
1420 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1421{
1422 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1423 {
1424 return;
1425 }
1426 std::optional<uint32_t> unlockTimeout;
1427 std::optional<uint16_t> lockoutThreshold;
1428 std::optional<uint8_t> minPasswordLength;
1429 std::optional<uint16_t> maxPasswordLength;
1430 std::optional<nlohmann::json> ldapObject;
1431 std::optional<nlohmann::json> activeDirectoryObject;
1432 std::optional<nlohmann::json> oemObject;
1433
1434 if (!json_util::readJsonPatch(
1435 req, asyncResp->res, "AccountLockoutDuration", unlockTimeout,
1436 "AccountLockoutThreshold", lockoutThreshold, "MaxPasswordLength",
1437 maxPasswordLength, "MinPasswordLength", minPasswordLength, "LDAP",
1438 ldapObject, "ActiveDirectory", activeDirectoryObject, "Oem",
1439 oemObject))
1440 {
1441 return;
1442 }
1443
1444 if (minPasswordLength)
1445 {
1446 crow::connections::systemBus->async_method_call(
1447 [asyncResp](const boost::system::error_code ec) {
1448 if (ec)
1449 {
1450 messages::internalError(asyncResp->res);
1451 return;
1452 }
1453 messages::success(asyncResp->res);
1454 },
1455 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
1456 "org.freedesktop.DBus.Properties", "Set",
1457 "xyz.openbmc_project.User.AccountPolicy", "MinPasswordLength",
1458 dbus::utility::DbusVariantType(*minPasswordLength));
1459 }
1460
1461 if (maxPasswordLength)
1462 {
1463 messages::propertyNotWritable(asyncResp->res, "MaxPasswordLength");
1464 }
1465
1466 if (ldapObject)
1467 {
1468 handleLDAPPatch(*ldapObject, asyncResp, "LDAP");
1469 }
1470
1471 if (std::optional<nlohmann::json> oemOpenBMCObject;
1472 oemObject && json_util::readJson(*oemObject, asyncResp->res, "OpenBMC",
1473 oemOpenBMCObject))
1474 {
1475 if (std::optional<nlohmann::json> authMethodsObject;
1476 oemOpenBMCObject &&
1477 json_util::readJson(*oemOpenBMCObject, asyncResp->res,
1478 "AuthMethods", authMethodsObject))
1479 {
1480 if (authMethodsObject)
1481 {
1482 handleAuthMethodsPatch(*authMethodsObject, asyncResp);
1483 }
1484 }
1485 }
1486
1487 if (activeDirectoryObject)
1488 {
1489 handleLDAPPatch(*activeDirectoryObject, asyncResp, "ActiveDirectory");
1490 }
1491
1492 if (unlockTimeout)
1493 {
1494 crow::connections::systemBus->async_method_call(
1495 [asyncResp](const boost::system::error_code ec) {
1496 if (ec)
1497 {
1498 messages::internalError(asyncResp->res);
1499 return;
1500 }
1501 messages::success(asyncResp->res);
1502 },
1503 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
1504 "org.freedesktop.DBus.Properties", "Set",
1505 "xyz.openbmc_project.User.AccountPolicy", "AccountUnlockTimeout",
1506 dbus::utility::DbusVariantType(*unlockTimeout));
1507 }
1508 if (lockoutThreshold)
1509 {
1510 crow::connections::systemBus->async_method_call(
1511 [asyncResp](const boost::system::error_code ec) {
1512 if (ec)
1513 {
1514 messages::internalError(asyncResp->res);
1515 return;
1516 }
1517 messages::success(asyncResp->res);
1518 },
1519 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
1520 "org.freedesktop.DBus.Properties", "Set",
1521 "xyz.openbmc_project.User.AccountPolicy",
1522 "MaxLoginAttemptBeforeLockout",
1523 dbus::utility::DbusVariantType(*lockoutThreshold));
1524 }
1525}
1526
Ed Tanous4c7d4d32022-07-07 15:29:35 -07001527inline void handleAccountCollectionHead(
Ed Tanous1ef4c342022-05-12 16:12:36 -07001528 App& app, const crow::Request& req,
1529 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1530{
Ed Tanous4c7d4d32022-07-07 15:29:35 -07001531
Ed Tanous1ef4c342022-05-12 16:12:36 -07001532 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1533 {
1534 return;
1535 }
Ed Tanous4c7d4d32022-07-07 15:29:35 -07001536 asyncResp->res.addHeader(
1537 boost::beast::http::field::link,
1538 "</redfish/v1/JsonSchemas/ManagerAccountCollection.json>; rel=describedby");
1539}
1540
1541inline void handleAccountCollectionGet(
1542 App& app, const crow::Request& req,
1543 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1544{
1545 handleAccountCollectionHead(app, req, asyncResp);
Ed Tanous1ef4c342022-05-12 16:12:36 -07001546
1547 asyncResp->res.jsonValue["@odata.id"] =
1548 "/redfish/v1/AccountService/Accounts";
1549 asyncResp->res.jsonValue["@odata.type"] = "#ManagerAccountCollection."
1550 "ManagerAccountCollection";
1551 asyncResp->res.jsonValue["Name"] = "Accounts Collection";
1552 asyncResp->res.jsonValue["Description"] = "BMC User Accounts";
1553
1554 Privileges effectiveUserPrivileges =
1555 redfish::getUserPrivileges(req.userRole);
1556
1557 std::string thisUser;
1558 if (req.session)
1559 {
1560 thisUser = req.session->username;
1561 }
1562 crow::connections::systemBus->async_method_call(
1563 [asyncResp, thisUser, effectiveUserPrivileges](
1564 const boost::system::error_code ec,
1565 const dbus::utility::ManagedObjectType& users) {
1566 if (ec)
1567 {
1568 messages::internalError(asyncResp->res);
1569 return;
1570 }
1571
1572 bool userCanSeeAllAccounts =
1573 effectiveUserPrivileges.isSupersetOf({"ConfigureUsers"});
1574
1575 bool userCanSeeSelf =
1576 effectiveUserPrivileges.isSupersetOf({"ConfigureSelf"});
1577
1578 nlohmann::json& memberArray = asyncResp->res.jsonValue["Members"];
1579 memberArray = nlohmann::json::array();
1580
1581 for (const auto& userpath : users)
1582 {
1583 std::string user = userpath.first.filename();
1584 if (user.empty())
1585 {
1586 messages::internalError(asyncResp->res);
1587 BMCWEB_LOG_ERROR << "Invalid firmware ID";
1588
1589 return;
1590 }
1591
1592 // As clarified by Redfish here:
1593 // https://redfishforum.com/thread/281/manageraccountcollection-change-allows-account-enumeration
1594 // Users without ConfigureUsers, only see their own
1595 // account. Users with ConfigureUsers, see all
1596 // accounts.
1597 if (userCanSeeAllAccounts || (thisUser == user && userCanSeeSelf))
1598 {
1599 nlohmann::json::object_t member;
1600 member["@odata.id"] =
1601 "/redfish/v1/AccountService/Accounts/" + user;
1602 memberArray.push_back(std::move(member));
1603 }
1604 }
1605 asyncResp->res.jsonValue["Members@odata.count"] = memberArray.size();
1606 },
1607 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
1608 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
1609}
1610
1611inline void handleAccountCollectionPost(
1612 App& app, const crow::Request& req,
1613 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1614{
1615 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1616 {
1617 return;
1618 }
1619 std::string username;
1620 std::string password;
1621 std::optional<std::string> roleId("User");
1622 std::optional<bool> enabled = true;
1623 if (!json_util::readJsonPatch(req, asyncResp->res, "UserName", username,
1624 "Password", password, "RoleId", roleId,
1625 "Enabled", enabled))
1626 {
1627 return;
1628 }
1629
1630 std::string priv = getPrivilegeFromRoleId(*roleId);
1631 if (priv.empty())
1632 {
1633 messages::propertyValueNotInList(asyncResp->res, *roleId, "RoleId");
1634 return;
1635 }
1636 // TODO: Following override will be reverted once support in
1637 // phosphor-user-manager is added. In order to avoid dependency
1638 // issues, this is added in bmcweb, which will removed, once
1639 // phosphor-user-manager supports priv-noaccess.
1640 if (priv == "priv-noaccess")
1641 {
1642 roleId = "";
1643 }
1644 else
1645 {
1646 roleId = priv;
1647 }
1648
1649 // Reading AllGroups property
1650 sdbusplus::asio::getProperty<std::vector<std::string>>(
1651 *crow::connections::systemBus, "xyz.openbmc_project.User.Manager",
1652 "/xyz/openbmc_project/user", "xyz.openbmc_project.User.Manager",
1653 "AllGroups",
1654 [asyncResp, username, password{std::move(password)}, roleId,
1655 enabled](const boost::system::error_code ec,
1656 const std::vector<std::string>& allGroupsList) {
1657 if (ec)
1658 {
1659 BMCWEB_LOG_DEBUG << "ERROR with async_method_call";
1660 messages::internalError(asyncResp->res);
1661 return;
1662 }
1663
1664 if (allGroupsList.empty())
1665 {
1666 messages::internalError(asyncResp->res);
1667 return;
1668 }
1669
1670 crow::connections::systemBus->async_method_call(
1671 [asyncResp, username, password](const boost::system::error_code ec2,
Patrick Williams59d494e2022-07-22 19:26:55 -05001672 sdbusplus::message_t& m) {
Ed Tanous1ef4c342022-05-12 16:12:36 -07001673 if (ec2)
1674 {
1675 userErrorMessageHandler(m.get_error(), asyncResp, username, "");
1676 return;
1677 }
1678
1679 if (pamUpdatePassword(username, password) != PAM_SUCCESS)
1680 {
1681 // At this point we have a user that's been
1682 // created, but the password set
1683 // failed.Something is wrong, so delete the user
1684 // that we've already created
1685 sdbusplus::message::object_path tempObjPath(rootUserDbusPath);
1686 tempObjPath /= username;
1687 const std::string userPath(tempObjPath);
1688
1689 crow::connections::systemBus->async_method_call(
1690 [asyncResp, password](const boost::system::error_code ec3) {
1691 if (ec3)
1692 {
1693 messages::internalError(asyncResp->res);
1694 return;
1695 }
1696
1697 // If password is invalid
1698 messages::propertyValueFormatError(asyncResp->res, password,
1699 "Password");
1700 },
1701 "xyz.openbmc_project.User.Manager", userPath,
1702 "xyz.openbmc_project.Object.Delete", "Delete");
1703
1704 BMCWEB_LOG_ERROR << "pamUpdatePassword Failed";
1705 return;
1706 }
1707
1708 messages::created(asyncResp->res);
1709 asyncResp->res.addHeader(
1710 "Location", "/redfish/v1/AccountService/Accounts/" + username);
1711 },
1712 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
1713 "xyz.openbmc_project.User.Manager", "CreateUser", username,
1714 allGroupsList, *roleId, *enabled);
1715 });
1716}
1717
1718inline void
Ed Tanous4c7d4d32022-07-07 15:29:35 -07001719 handleAccountHead(App& app, const crow::Request& req,
1720 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1721 const std::string& /*accountName*/)
Ed Tanous1ef4c342022-05-12 16:12:36 -07001722{
Ed Tanous4c7d4d32022-07-07 15:29:35 -07001723
Ed Tanous1ef4c342022-05-12 16:12:36 -07001724 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1725 {
1726 return;
1727 }
Ed Tanous4c7d4d32022-07-07 15:29:35 -07001728 asyncResp->res.addHeader(
1729 boost::beast::http::field::link,
1730 "</redfish/v1/JsonSchemas/ManagerAccount/ManagerAccount.json>; rel=describedby");
1731}
1732inline void
1733 handleAccountGet(App& app, const crow::Request& req,
1734 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1735 const std::string& accountName)
1736{
1737 handleAccountHead(app, req, asyncResp, accountName);
Ed Tanous1ef4c342022-05-12 16:12:36 -07001738#ifdef BMCWEB_INSECURE_DISABLE_AUTHENTICATION
1739 // If authentication is disabled, there are no user accounts
Jiaqing Zhaod8a5d5d2022-08-05 16:21:51 +08001740 messages::resourceNotFound(asyncResp->res, "ManagerAccount", accountName);
Ed Tanous1ef4c342022-05-12 16:12:36 -07001741 return;
1742
1743#endif // BMCWEB_INSECURE_DISABLE_AUTHENTICATION
1744 if (req.session == nullptr)
1745 {
1746 messages::internalError(asyncResp->res);
1747 return;
1748 }
1749 if (req.session->username != accountName)
1750 {
1751 // At this point we've determined that the user is trying to
1752 // modify a user that isn't them. We need to verify that they
1753 // have permissions to modify other users, so re-run the auth
1754 // check with the same permissions, minus ConfigureSelf.
1755 Privileges effectiveUserPrivileges =
1756 redfish::getUserPrivileges(req.userRole);
1757 Privileges requiredPermissionsToChangeNonSelf = {"ConfigureUsers",
1758 "ConfigureManager"};
1759 if (!effectiveUserPrivileges.isSupersetOf(
1760 requiredPermissionsToChangeNonSelf))
1761 {
1762 BMCWEB_LOG_DEBUG << "GET Account denied access";
1763 messages::insufficientPrivilege(asyncResp->res);
1764 return;
1765 }
1766 }
1767
1768 crow::connections::systemBus->async_method_call(
1769 [asyncResp,
1770 accountName](const boost::system::error_code ec,
1771 const dbus::utility::ManagedObjectType& users) {
1772 if (ec)
1773 {
1774 messages::internalError(asyncResp->res);
1775 return;
1776 }
1777 const auto userIt = std::find_if(
1778 users.begin(), users.end(),
1779 [accountName](
1780 const std::pair<sdbusplus::message::object_path,
1781 dbus::utility::DBusInteracesMap>& user) {
1782 return accountName == user.first.filename();
1783 });
1784
1785 if (userIt == users.end())
1786 {
1787 messages::resourceNotFound(asyncResp->res, "ManagerAccount",
1788 accountName);
1789 return;
1790 }
1791
1792 asyncResp->res.jsonValue["@odata.type"] =
1793 "#ManagerAccount.v1_4_0.ManagerAccount";
1794 asyncResp->res.jsonValue["Name"] = "User Account";
1795 asyncResp->res.jsonValue["Description"] = "User Account";
1796 asyncResp->res.jsonValue["Password"] = nullptr;
Ed Tanous1ef4c342022-05-12 16:12:36 -07001797
1798 for (const auto& interface : userIt->second)
1799 {
1800 if (interface.first == "xyz.openbmc_project.User.Attributes")
1801 {
1802 for (const auto& property : interface.second)
1803 {
1804 if (property.first == "UserEnabled")
1805 {
1806 const bool* userEnabled =
1807 std::get_if<bool>(&property.second);
1808 if (userEnabled == nullptr)
1809 {
1810 BMCWEB_LOG_ERROR << "UserEnabled wasn't a bool";
1811 messages::internalError(asyncResp->res);
1812 return;
1813 }
1814 asyncResp->res.jsonValue["Enabled"] = *userEnabled;
1815 }
1816 else if (property.first == "UserLockedForFailedAttempt")
1817 {
1818 const bool* userLocked =
1819 std::get_if<bool>(&property.second);
1820 if (userLocked == nullptr)
1821 {
1822 BMCWEB_LOG_ERROR << "UserLockedForF"
1823 "ailedAttempt "
1824 "wasn't a bool";
1825 messages::internalError(asyncResp->res);
1826 return;
1827 }
1828 asyncResp->res.jsonValue["Locked"] = *userLocked;
1829 asyncResp->res
1830 .jsonValue["Locked@Redfish.AllowableValues"] = {
1831 "false"}; // can only unlock accounts
1832 }
1833 else if (property.first == "UserPrivilege")
1834 {
1835 const std::string* userPrivPtr =
1836 std::get_if<std::string>(&property.second);
1837 if (userPrivPtr == nullptr)
1838 {
1839 BMCWEB_LOG_ERROR << "UserPrivilege wasn't a "
1840 "string";
1841 messages::internalError(asyncResp->res);
1842 return;
1843 }
1844 std::string role = getRoleIdFromPrivilege(*userPrivPtr);
1845 if (role.empty())
1846 {
1847 BMCWEB_LOG_ERROR << "Invalid user role";
1848 messages::internalError(asyncResp->res);
1849 return;
1850 }
1851 asyncResp->res.jsonValue["RoleId"] = role;
1852
1853 nlohmann::json& roleEntry =
1854 asyncResp->res.jsonValue["Links"]["Role"];
1855 roleEntry["@odata.id"] =
1856 "/redfish/v1/AccountService/Roles/" + role;
1857 }
1858 else if (property.first == "UserPasswordExpired")
1859 {
1860 const bool* userPasswordExpired =
1861 std::get_if<bool>(&property.second);
1862 if (userPasswordExpired == nullptr)
1863 {
1864 BMCWEB_LOG_ERROR
1865 << "UserPasswordExpired wasn't a bool";
1866 messages::internalError(asyncResp->res);
1867 return;
1868 }
1869 asyncResp->res.jsonValue["PasswordChangeRequired"] =
1870 *userPasswordExpired;
1871 }
Abhishek Patelc7229812022-02-01 10:07:15 -06001872 else if (property.first == "UserGroups")
1873 {
1874 const std::vector<std::string>* userGroups =
1875 std::get_if<std::vector<std::string>>(
1876 &property.second);
1877 if (userGroups == nullptr)
1878 {
1879 BMCWEB_LOG_ERROR
1880 << "userGroups wasn't a string vector";
1881 messages::internalError(asyncResp->res);
1882 return;
1883 }
1884 if (!translateUserGroup(*userGroups, asyncResp->res))
1885 {
1886 BMCWEB_LOG_ERROR << "userGroups mapping failed";
1887 messages::internalError(asyncResp->res);
1888 return;
1889 }
1890 }
Ed Tanous1ef4c342022-05-12 16:12:36 -07001891 }
1892 }
1893 }
1894
1895 asyncResp->res.jsonValue["@odata.id"] =
1896 "/redfish/v1/AccountService/Accounts/" + accountName;
1897 asyncResp->res.jsonValue["Id"] = accountName;
1898 asyncResp->res.jsonValue["UserName"] = accountName;
1899 },
1900 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
1901 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
1902}
1903
1904inline void
1905 handleAccounttDelete(App& app, const crow::Request& req,
1906 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1907 const std::string& username)
1908{
1909 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1910 {
1911 return;
1912 }
1913
1914#ifdef BMCWEB_INSECURE_DISABLE_AUTHENTICATION
1915 // If authentication is disabled, there are no user accounts
Jiaqing Zhaod8a5d5d2022-08-05 16:21:51 +08001916 messages::resourceNotFound(asyncResp->res, "ManagerAccount", username);
Ed Tanous1ef4c342022-05-12 16:12:36 -07001917 return;
1918
1919#endif // BMCWEB_INSECURE_DISABLE_AUTHENTICATION
1920 sdbusplus::message::object_path tempObjPath(rootUserDbusPath);
1921 tempObjPath /= username;
1922 const std::string userPath(tempObjPath);
1923
1924 crow::connections::systemBus->async_method_call(
1925 [asyncResp, username](const boost::system::error_code ec) {
1926 if (ec)
1927 {
Jiaqing Zhaod8a5d5d2022-08-05 16:21:51 +08001928 messages::resourceNotFound(asyncResp->res, "ManagerAccount",
Ed Tanous1ef4c342022-05-12 16:12:36 -07001929 username);
1930 return;
1931 }
1932
1933 messages::accountRemoved(asyncResp->res);
1934 },
1935 "xyz.openbmc_project.User.Manager", userPath,
1936 "xyz.openbmc_project.Object.Delete", "Delete");
1937}
1938
1939inline void
1940 handleAccountPatch(App& app, const crow::Request& req,
1941 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1942 const std::string& username)
1943{
1944 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1945 {
1946 return;
1947 }
1948#ifdef BMCWEB_INSECURE_DISABLE_AUTHENTICATION
1949 // If authentication is disabled, there are no user accounts
Jiaqing Zhaod8a5d5d2022-08-05 16:21:51 +08001950 messages::resourceNotFound(asyncResp->res, "ManagerAccount", username);
Ed Tanous1ef4c342022-05-12 16:12:36 -07001951 return;
1952
1953#endif // BMCWEB_INSECURE_DISABLE_AUTHENTICATION
1954 std::optional<std::string> newUserName;
1955 std::optional<std::string> password;
1956 std::optional<bool> enabled;
1957 std::optional<std::string> roleId;
1958 std::optional<bool> locked;
1959
1960 if (req.session == nullptr)
1961 {
1962 messages::internalError(asyncResp->res);
1963 return;
1964 }
1965
1966 Privileges effectiveUserPrivileges =
1967 redfish::getUserPrivileges(req.userRole);
1968 Privileges configureUsers = {"ConfigureUsers"};
1969 bool userHasConfigureUsers =
1970 effectiveUserPrivileges.isSupersetOf(configureUsers);
1971 if (userHasConfigureUsers)
1972 {
1973 // Users with ConfigureUsers can modify for all users
1974 if (!json_util::readJsonPatch(req, asyncResp->res, "UserName",
1975 newUserName, "Password", password,
1976 "RoleId", roleId, "Enabled", enabled,
1977 "Locked", locked))
1978 {
1979 return;
1980 }
1981 }
1982 else
1983 {
1984 // ConfigureSelf accounts can only modify their own account
1985 if (username != req.session->username)
1986 {
1987 messages::insufficientPrivilege(asyncResp->res);
1988 return;
1989 }
1990
1991 // ConfigureSelf accounts can only modify their password
1992 if (!json_util::readJsonPatch(req, asyncResp->res, "Password",
1993 password))
1994 {
1995 return;
1996 }
1997 }
1998
1999 // if user name is not provided in the patch method or if it
2000 // matches the user name in the URI, then we are treating it as
2001 // updating user properties other then username. If username
2002 // provided doesn't match the URI, then we are treating this as
2003 // user rename request.
2004 if (!newUserName || (newUserName.value() == username))
2005 {
2006 updateUserProperties(asyncResp, username, password, enabled, roleId,
2007 locked);
2008 return;
2009 }
2010 crow::connections::systemBus->async_method_call(
2011 [asyncResp, username, password(std::move(password)),
2012 roleId(std::move(roleId)), enabled, newUser{std::string(*newUserName)},
Patrick Williams59d494e2022-07-22 19:26:55 -05002013 locked](const boost::system::error_code ec, sdbusplus::message_t& m) {
Ed Tanous1ef4c342022-05-12 16:12:36 -07002014 if (ec)
2015 {
2016 userErrorMessageHandler(m.get_error(), asyncResp, newUser,
2017 username);
2018 return;
2019 }
2020
2021 updateUserProperties(asyncResp, newUser, password, enabled, roleId,
2022 locked);
2023 },
2024 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
2025 "xyz.openbmc_project.User.Manager", "RenameUser", username,
2026 *newUserName);
2027}
2028
Ed Tanous6c51eab2021-06-03 12:30:29 -07002029inline void requestAccountServiceRoutes(App& app)
Ed Tanousb9b2e0b2018-09-13 13:47:50 -07002030{
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_)(
Ed Tanous1ef4c342022-05-12 16:12:36 -07002083 std::bind_front(handleAccounttDelete, 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