blob: fa10c04dd34e44d2c14ffc0fb35847574b343518 [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#include "node.hpp"
18
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 Tanousa8408792018-09-05 16:08:38 -070022#include <utils/json_utils.hpp>
Ed Tanousabf2add2019-01-22 16:40:12 -080023#include <variant>
Ed Tanousb9b2e0b2018-09-13 13:47:50 -070024
Ed Tanous1abe55e2018-09-05 08:30:59 -070025namespace redfish
26{
Lewanczyk, Dawid88d16c92018-02-02 14:51:09 +010027
Ratan Gupta6973a582018-12-13 18:25:44 +053028constexpr const char* ldapConfigObject =
29 "/xyz/openbmc_project/user/ldap/openldap";
Ratan Guptaab828d72019-04-22 14:18:33 +053030constexpr const char* ADConfigObject =
31 "/xyz/openbmc_project/user/ldap/active_directory";
32
Ratan Gupta6973a582018-12-13 18:25:44 +053033constexpr const char* ldapRootObject = "/xyz/openbmc_project/user/ldap";
34constexpr const char* ldapDbusService = "xyz.openbmc_project.Ldap.Config";
35constexpr const char* ldapConfigInterface =
36 "xyz.openbmc_project.User.Ldap.Config";
37constexpr const char* ldapCreateInterface =
38 "xyz.openbmc_project.User.Ldap.Create";
39constexpr const char* ldapEnableInterface = "xyz.openbmc_project.Object.Enable";
Ratan Gupta06785242019-07-26 22:30:16 +053040constexpr const char* ldapPrivMapperInterface =
41 "xyz.openbmc_project.User.PrivilegeMapper";
Ratan Gupta6973a582018-12-13 18:25:44 +053042constexpr const char* dbusObjManagerIntf = "org.freedesktop.DBus.ObjectManager";
43constexpr const char* propertyInterface = "org.freedesktop.DBus.Properties";
44constexpr const char* mapperBusName = "xyz.openbmc_project.ObjectMapper";
45constexpr const char* mapperObjectPath = "/xyz/openbmc_project/object_mapper";
46constexpr const char* mapperIntf = "xyz.openbmc_project.ObjectMapper";
47
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -060048struct LDAPRoleMapData
49{
50 std::string groupName;
51 std::string privilege;
52};
53
Ratan Gupta6973a582018-12-13 18:25:44 +053054struct LDAPConfigData
55{
56 std::string uri{};
57 std::string bindDN{};
58 std::string baseDN{};
59 std::string searchScope{};
60 std::string serverType{};
61 bool serviceEnabled = false;
62 std::string userNameAttribute{};
63 std::string groupAttribute{};
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -060064 std::vector<std::pair<std::string, LDAPRoleMapData>> groupRoleList;
Ratan Gupta6973a582018-12-13 18:25:44 +053065};
66
Ed Tanousb9b2e0b2018-09-13 13:47:50 -070067using ManagedObjectType = std::vector<std::pair<
68 sdbusplus::message::object_path,
69 boost::container::flat_map<
Ed Tanousabf2add2019-01-22 16:40:12 -080070 std::string, boost::container::flat_map<
71 std::string, std::variant<bool, std::string>>>>>;
Ratan Gupta6973a582018-12-13 18:25:44 +053072using GetObjectType =
73 std::vector<std::pair<std::string, std::vector<std::string>>>;
AppaRao Puli84e12cb2018-10-11 01:28:15 +053074
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -060075inline std::string getRoleIdFromPrivilege(std::string_view role)
AppaRao Puli84e12cb2018-10-11 01:28:15 +053076{
77 if (role == "priv-admin")
78 {
79 return "Administrator";
80 }
AppaRao Puli84e12cb2018-10-11 01:28:15 +053081 else if (role == "priv-user")
82 {
AppaRao Pulic80fee52019-10-16 14:49:36 +053083 return "ReadOnly";
AppaRao Puli84e12cb2018-10-11 01:28:15 +053084 }
85 else if (role == "priv-operator")
86 {
87 return "Operator";
88 }
89 return "";
90}
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -060091inline std::string getPrivilegeFromRoleId(std::string_view role)
AppaRao Puli84e12cb2018-10-11 01:28:15 +053092{
93 if (role == "Administrator")
94 {
95 return "priv-admin";
96 }
AppaRao Pulic80fee52019-10-16 14:49:36 +053097 else if (role == "ReadOnly")
AppaRao Puli84e12cb2018-10-11 01:28:15 +053098 {
99 return "priv-user";
100 }
101 else if (role == "Operator")
102 {
103 return "priv-operator";
104 }
105 return "";
106}
Ed Tanousb9b2e0b2018-09-13 13:47:50 -0700107
jayaprakash Mutyala66b5ca72019-08-07 20:26:37 +0000108void userErrorMessageHandler(const sd_bus_error* e,
109 std::shared_ptr<AsyncResp> asyncResp,
110 const std::string& newUser,
111 const std::string& username)
112{
113 const char* errorMessage = e->name;
114 if (e == nullptr)
115 {
116 messages::internalError(asyncResp->res);
117 return;
118 }
119
120 if (strcmp(errorMessage,
121 "xyz.openbmc_project.User.Common.Error.UserNameExists") == 0)
122 {
123 messages::resourceAlreadyExists(asyncResp->res,
124 "#ManagerAccount.v1_0_3.ManagerAccount",
125 "UserName", newUser);
126 }
127 else if (strcmp(errorMessage, "xyz.openbmc_project.User.Common.Error."
128 "UserNameDoesNotExist") == 0)
129 {
130 messages::resourceNotFound(
131 asyncResp->res, "#ManagerAccount.v1_0_3.ManagerAccount", username);
132 }
133 else if (strcmp(errorMessage,
134 "xyz.openbmc_project.Common.Error.InvalidArgument") == 0)
135 {
136 messages::propertyValueFormatError(asyncResp->res, newUser, "UserName");
137 }
138 else if (strcmp(errorMessage,
139 "xyz.openbmc_project.User.Common.Error.NoResource") == 0)
140 {
141 messages::createLimitReachedForResource(asyncResp->res);
142 }
143 else if (strcmp(errorMessage, "xyz.openbmc_project.User.Common.Error."
144 "UserNameGroupFail") == 0)
145 {
146 messages::propertyValueFormatError(asyncResp->res, newUser, "UserName");
147 }
148 else
149 {
150 messages::internalError(asyncResp->res);
151 }
152
153 return;
154}
155
Ratan Gupta6973a582018-12-13 18:25:44 +0530156void parseLDAPConfigData(nlohmann::json& json_response,
Ratan Guptaab828d72019-04-22 14:18:33 +0530157 const LDAPConfigData& confData,
158 const std::string& ldapType)
Ratan Gupta6973a582018-12-13 18:25:44 +0530159{
Ratan Guptaab828d72019-04-22 14:18:33 +0530160 std::string service =
161 (ldapType == "LDAP") ? "LDAPService" : "ActiveDirectoryService";
Marri Devender Rao37cce912019-02-20 01:05:22 -0600162 nlohmann::json ldap = {
Ratan Gupta6973a582018-12-13 18:25:44 +0530163 {"AccountProviderType", service},
Ratan Gupta6973a582018-12-13 18:25:44 +0530164 {"ServiceEnabled", confData.serviceEnabled},
165 {"ServiceAddresses", nlohmann::json::array({confData.uri})},
166 {"Authentication",
167 {{"AuthenticationType", "UsernameAndPassword"},
Ratan Gupta6973a582018-12-13 18:25:44 +0530168 {"Username", confData.bindDN},
169 {"Password", nullptr}}},
170 {"LDAPService",
171 {{"SearchSettings",
172 {{"BaseDistinguishedNames",
173 nlohmann::json::array({confData.baseDN})},
174 {"UsernameAttribute", confData.userNameAttribute},
175 {"GroupsAttribute", confData.groupAttribute}}}}},
176 };
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600177
Marri Devender Rao37cce912019-02-20 01:05:22 -0600178 json_response[ldapType].update(std::move(ldap));
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600179
180 nlohmann::json& roleMapArray = json_response[ldapType]["RemoteRoleMapping"];
181 roleMapArray = nlohmann::json::array();
182 for (auto& obj : confData.groupRoleList)
183 {
184 BMCWEB_LOG_DEBUG << "Pushing the data groupName="
185 << obj.second.groupName << "\n";
186 roleMapArray.push_back(
187 {nlohmann::json::array({"RemoteGroup", obj.second.groupName}),
188 nlohmann::json::array(
189 {"LocalRole", getRoleIdFromPrivilege(obj.second.privilege)})});
190 }
Ratan Gupta6973a582018-12-13 18:25:44 +0530191}
192
193/**
Ratan Gupta06785242019-07-26 22:30:16 +0530194 * @brief validates given JSON input and then calls appropriate method to
195 * create, to delete or to set Rolemapping object based on the given input.
196 *
197 */
198static void handleRoleMapPatch(
199 const std::shared_ptr<AsyncResp>& asyncResp,
200 const std::vector<std::pair<std::string, LDAPRoleMapData>>& roleMapObjData,
201 const std::string& serverType, std::vector<nlohmann::json>& input)
202{
203 for (size_t index = 0; index < input.size(); index++)
204 {
205 nlohmann::json& thisJson = input[index];
206
207 if (thisJson.is_null())
208 {
209 // delete the existing object
210 if (index < roleMapObjData.size())
211 {
212 crow::connections::systemBus->async_method_call(
213 [asyncResp, roleMapObjData, serverType,
214 index](const boost::system::error_code ec) {
215 if (ec)
216 {
217 BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
218 messages::internalError(asyncResp->res);
219 return;
220 }
221 asyncResp->res
222 .jsonValue[serverType]["RemoteRoleMapping"][index] =
223 nullptr;
224 },
225 ldapDbusService, roleMapObjData[index].first,
226 "xyz.openbmc_project.Object.Delete", "Delete");
227 }
228 else
229 {
230 BMCWEB_LOG_ERROR << "Can't delete the object";
231 messages::propertyValueTypeError(
232 asyncResp->res, thisJson.dump(),
233 "RemoteRoleMapping/" + std::to_string(index));
234 return;
235 }
236 }
237 else if (thisJson.empty())
238 {
239 // Don't do anything for the empty objects,parse next json
240 // eg {"RemoteRoleMapping",[{}]}
241 }
242 else
243 {
244 // update/create the object
245 std::optional<std::string> remoteGroup;
246 std::optional<std::string> localRole;
247
248 if (!json_util::readJson(thisJson, asyncResp->res, "RemoteGroup",
249 remoteGroup, "LocalRole", localRole))
250 {
251 continue;
252 }
253
254 // Update existing RoleMapping Object
255 if (index < roleMapObjData.size())
256 {
257 BMCWEB_LOG_DEBUG << "Update Role Map Object";
258 // If "RemoteGroup" info is provided
259 if (remoteGroup)
260 {
261 crow::connections::systemBus->async_method_call(
262 [asyncResp, roleMapObjData, serverType, index,
263 remoteGroup](const boost::system::error_code ec) {
264 if (ec)
265 {
266 BMCWEB_LOG_ERROR << "DBUS response error: "
267 << ec;
268 messages::internalError(asyncResp->res);
269 return;
270 }
271 asyncResp->res
272 .jsonValue[serverType]["RemoteRoleMapping"]
273 [index]["RemoteGroup"] = *remoteGroup;
274 },
275 ldapDbusService, roleMapObjData[index].first,
276 propertyInterface, "Set",
277 "xyz.openbmc_project.User.PrivilegeMapperEntry",
278 "GroupName",
279 std::variant<std::string>(std::move(*remoteGroup)));
280 }
281
282 // If "LocalRole" info is provided
283 if (localRole)
284 {
285 crow::connections::systemBus->async_method_call(
286 [asyncResp, roleMapObjData, serverType, index,
287 localRole](const boost::system::error_code ec) {
288 if (ec)
289 {
290 BMCWEB_LOG_ERROR << "DBUS response error: "
291 << ec;
292 messages::internalError(asyncResp->res);
293 return;
294 }
295 asyncResp->res
296 .jsonValue[serverType]["RemoteRoleMapping"]
297 [index]["LocalRole"] = *localRole;
298 },
299 ldapDbusService, roleMapObjData[index].first,
300 propertyInterface, "Set",
301 "xyz.openbmc_project.User.PrivilegeMapperEntry",
302 "Privilege",
303 std::variant<std::string>(
304 getPrivilegeFromRoleId(std::move(*localRole))));
305 }
306 }
307 // Create a new RoleMapping Object.
308 else
309 {
310 BMCWEB_LOG_DEBUG
311 << "setRoleMappingProperties: Creating new Object";
312 std::string pathString =
313 "RemoteRoleMapping/" + std::to_string(index);
314
315 if (!localRole)
316 {
317 messages::propertyMissing(asyncResp->res,
318 pathString + "/LocalRole");
319 continue;
320 }
321 if (!remoteGroup)
322 {
323 messages::propertyMissing(asyncResp->res,
324 pathString + "/RemoteGroup");
325 continue;
326 }
327
328 std::string dbusObjectPath;
329 if (serverType == "ActiveDirectory")
330 {
331 dbusObjectPath = ADConfigObject;
332 }
333 else if (serverType == "LDAP")
334 {
335 dbusObjectPath = ldapConfigObject;
336 }
337
338 BMCWEB_LOG_DEBUG << "Remote Group=" << *remoteGroup
339 << ",LocalRole=" << *localRole;
340
341 crow::connections::systemBus->async_method_call(
Ed Tanous271584a2019-07-09 16:24:22 -0700342 [asyncResp, serverType, localRole,
Ratan Gupta06785242019-07-26 22:30:16 +0530343 remoteGroup](const boost::system::error_code ec) {
344 if (ec)
345 {
346 BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
347 messages::internalError(asyncResp->res);
348 return;
349 }
350 nlohmann::json& remoteRoleJson =
351 asyncResp->res
352 .jsonValue[serverType]["RemoteRoleMapping"];
353 remoteRoleJson.push_back(
354 {{"LocalRole", *localRole},
355 {"RemoteGroup", *remoteGroup}});
356 },
357 ldapDbusService, dbusObjectPath, ldapPrivMapperInterface,
358 "Create", std::move(*remoteGroup),
359 getPrivilegeFromRoleId(std::move(*localRole)));
360 }
361 }
362 }
363}
364
365/**
Ratan Gupta6973a582018-12-13 18:25:44 +0530366 * Function that retrieves all properties for LDAP config object
367 * into JSON
368 */
369template <typename CallbackFunc>
370inline void getLDAPConfigData(const std::string& ldapType,
371 CallbackFunc&& callback)
372{
Ratan Guptaab828d72019-04-22 14:18:33 +0530373
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600374 const std::array<const char*, 2> interfaces = {ldapEnableInterface,
Ratan Gupta6973a582018-12-13 18:25:44 +0530375 ldapConfigInterface};
376
377 crow::connections::systemBus->async_method_call(
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600378 [callback, ldapType](const boost::system::error_code ec,
379 const GetObjectType& resp) {
380 LDAPConfigData confData{};
381 if (ec || resp.empty())
382 {
383 BMCWEB_LOG_ERROR << "DBUS response error during getting of "
384 "service name: "
385 << ec;
386 callback(false, confData, ldapType);
387 return;
388 }
389 std::string service = resp.begin()->first;
390 crow::connections::systemBus->async_method_call(
391 [callback, ldapType](const boost::system::error_code error_code,
392 const ManagedObjectType& ldapObjects) {
393 LDAPConfigData confData{};
394 if (error_code)
395 {
396 callback(false, confData, ldapType);
397 BMCWEB_LOG_ERROR << "D-Bus responses error: "
398 << error_code;
399 return;
400 }
401
402 std::string ldapDbusType;
403 std::string searchString;
404
405 if (ldapType == "LDAP")
406 {
407 ldapDbusType = "xyz.openbmc_project.User.Ldap.Config."
408 "Type.OpenLdap";
409 searchString = "openldap";
410 }
411 else if (ldapType == "ActiveDirectory")
412 {
413 ldapDbusType =
414 "xyz.openbmc_project.User.Ldap.Config.Type."
415 "ActiveDirectory";
416 searchString = "active_directory";
417 }
418 else
419 {
420 BMCWEB_LOG_ERROR
421 << "Can't get the DbusType for the given type="
422 << ldapType;
423 callback(false, confData, ldapType);
424 return;
425 }
426
427 std::string ldapEnableInterfaceStr = ldapEnableInterface;
428 std::string ldapConfigInterfaceStr = ldapConfigInterface;
429
430 for (const auto& object : ldapObjects)
431 {
432 // let's find the object whose ldap type is equal to the
433 // given type
434 if (object.first.str.find(searchString) ==
435 std::string::npos)
436 {
437 continue;
438 }
439
440 for (const auto& interface : object.second)
441 {
442 if (interface.first == ldapEnableInterfaceStr)
443 {
444 // rest of the properties are string.
445 for (const auto& property : interface.second)
446 {
447 if (property.first == "Enabled")
448 {
449 const bool* value =
450 std::get_if<bool>(&property.second);
451 if (value == nullptr)
452 {
453 continue;
454 }
455 confData.serviceEnabled = *value;
456 break;
457 }
458 }
459 }
460 else if (interface.first == ldapConfigInterfaceStr)
461 {
462
463 for (const auto& property : interface.second)
464 {
Ed Tanous271584a2019-07-09 16:24:22 -0700465 const std::string* strValue =
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600466 std::get_if<std::string>(
467 &property.second);
Ed Tanous271584a2019-07-09 16:24:22 -0700468 if (strValue == nullptr)
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600469 {
470 continue;
471 }
472 if (property.first == "LDAPServerURI")
473 {
Ed Tanous271584a2019-07-09 16:24:22 -0700474 confData.uri = *strValue;
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600475 }
476 else if (property.first == "LDAPBindDN")
477 {
Ed Tanous271584a2019-07-09 16:24:22 -0700478 confData.bindDN = *strValue;
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600479 }
480 else if (property.first == "LDAPBaseDN")
481 {
Ed Tanous271584a2019-07-09 16:24:22 -0700482 confData.baseDN = *strValue;
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600483 }
484 else if (property.first ==
485 "LDAPSearchScope")
486 {
Ed Tanous271584a2019-07-09 16:24:22 -0700487 confData.searchScope = *strValue;
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600488 }
489 else if (property.first ==
490 "GroupNameAttribute")
491 {
Ed Tanous271584a2019-07-09 16:24:22 -0700492 confData.groupAttribute = *strValue;
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600493 }
494 else if (property.first ==
495 "UserNameAttribute")
496 {
Ed Tanous271584a2019-07-09 16:24:22 -0700497 confData.userNameAttribute = *strValue;
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600498 }
499 else if (property.first == "LDAPType")
500 {
Ed Tanous271584a2019-07-09 16:24:22 -0700501 confData.serverType = *strValue;
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600502 }
503 }
504 }
505 else if (interface.first ==
506 "xyz.openbmc_project.User."
507 "PrivilegeMapperEntry")
508 {
509 LDAPRoleMapData roleMapData{};
510 for (const auto& property : interface.second)
511 {
Ed Tanous271584a2019-07-09 16:24:22 -0700512 const std::string* strValue =
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600513 std::get_if<std::string>(
514 &property.second);
515
Ed Tanous271584a2019-07-09 16:24:22 -0700516 if (strValue == nullptr)
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600517 {
518 continue;
519 }
520
521 if (property.first == "GroupName")
522 {
Ed Tanous271584a2019-07-09 16:24:22 -0700523 roleMapData.groupName = *strValue;
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600524 }
525 else if (property.first == "Privilege")
526 {
Ed Tanous271584a2019-07-09 16:24:22 -0700527 roleMapData.privilege = *strValue;
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600528 }
529 }
530
Ed Tanous0f0353b2019-10-24 11:37:51 -0700531 confData.groupRoleList.emplace_back(
532 object.first.str, roleMapData);
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -0600533 }
534 }
535 }
536 callback(true, confData, ldapType);
537 },
538 service, ldapRootObject, dbusObjManagerIntf,
539 "GetManagedObjects");
540 },
541 mapperBusName, mapperObjectPath, mapperIntf, "GetObject",
542 ldapConfigObject, interfaces);
Ratan Gupta6973a582018-12-13 18:25:44 +0530543}
544
Ed Tanous1abe55e2018-09-05 08:30:59 -0700545class AccountService : public Node
546{
547 public:
Zbigniew Kurzynski78158632019-11-05 12:57:37 +0100548 AccountService(CrowApp& app) :
549 Node(app, "/redfish/v1/AccountService/"), app(app)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700550 {
Ed Tanous1abe55e2018-09-05 08:30:59 -0700551 entityPrivileges = {
552 {boost::beast::http::verb::get,
553 {{"ConfigureUsers"}, {"ConfigureManager"}}},
554 {boost::beast::http::verb::head, {{"Login"}}},
555 {boost::beast::http::verb::patch, {{"ConfigureUsers"}}},
556 {boost::beast::http::verb::put, {{"ConfigureUsers"}}},
557 {boost::beast::http::verb::delete_, {{"ConfigureUsers"}}},
558 {boost::beast::http::verb::post, {{"ConfigureUsers"}}}};
559 }
Lewanczyk, Dawid88d16c92018-02-02 14:51:09 +0100560
Ed Tanous1abe55e2018-09-05 08:30:59 -0700561 private:
Ratan Gupta8a07d282019-03-16 08:33:47 +0530562 /**
563 * @brief parses the authentication section under the LDAP
564 * @param input JSON data
565 * @param asyncResp pointer to the JSON response
566 * @param userName userName to be filled from the given JSON.
567 * @param password password to be filled from the given JSON.
568 */
569 void
570 parseLDAPAuthenticationJson(nlohmann::json input,
571 const std::shared_ptr<AsyncResp>& asyncResp,
572 std::optional<std::string>& username,
573 std::optional<std::string>& password)
574 {
575 std::optional<std::string> authType;
576
577 if (!json_util::readJson(input, asyncResp->res, "AuthenticationType",
578 authType, "Username", username, "Password",
579 password))
580 {
581 return;
582 }
583 if (!authType)
584 {
585 return;
586 }
587 if (*authType != "UsernameAndPassword")
588 {
589 messages::propertyValueNotInList(asyncResp->res, *authType,
590 "AuthenticationType");
591 return;
592 }
593 }
594 /**
595 * @brief parses the LDAPService section under the LDAP
596 * @param input JSON data
597 * @param asyncResp pointer to the JSON response
598 * @param baseDNList baseDN to be filled from the given JSON.
599 * @param userNameAttribute userName to be filled from the given JSON.
600 * @param groupaAttribute password to be filled from the given JSON.
601 */
602
603 void parseLDAPServiceJson(
604 nlohmann::json input, const std::shared_ptr<AsyncResp>& asyncResp,
605 std::optional<std::vector<std::string>>& baseDNList,
606 std::optional<std::string>& userNameAttribute,
607 std::optional<std::string>& groupsAttribute)
608 {
609 std::optional<nlohmann::json> searchSettings;
610
611 if (!json_util::readJson(input, asyncResp->res, "SearchSettings",
612 searchSettings))
613 {
614 return;
615 }
616 if (!searchSettings)
617 {
618 return;
619 }
620 if (!json_util::readJson(*searchSettings, asyncResp->res,
621 "BaseDistinguishedNames", baseDNList,
622 "UsernameAttribute", userNameAttribute,
623 "GroupsAttribute", groupsAttribute))
624 {
625 return;
626 }
627 }
628 /**
629 * @brief updates the LDAP server address and updates the
630 json response with the new value.
631 * @param serviceAddressList address to be updated.
632 * @param asyncResp pointer to the JSON response
633 * @param ldapServerElementName Type of LDAP
634 server(openLDAP/ActiveDirectory)
635 */
636
637 void handleServiceAddressPatch(
638 const std::vector<std::string>& serviceAddressList,
639 const std::shared_ptr<AsyncResp>& asyncResp,
640 const std::string& ldapServerElementName,
641 const std::string& ldapConfigObject)
642 {
643 crow::connections::systemBus->async_method_call(
644 [asyncResp, ldapServerElementName,
645 serviceAddressList](const boost::system::error_code ec) {
646 if (ec)
647 {
648 BMCWEB_LOG_DEBUG
649 << "Error Occured in updating the service address";
650 messages::internalError(asyncResp->res);
651 return;
652 }
653 std::vector<std::string> modifiedserviceAddressList = {
654 serviceAddressList.front()};
655 asyncResp->res
656 .jsonValue[ldapServerElementName]["ServiceAddresses"] =
657 modifiedserviceAddressList;
658 if ((serviceAddressList).size() > 1)
659 {
660 messages::propertyValueModified(asyncResp->res,
661 "ServiceAddresses",
662 serviceAddressList.front());
663 }
664 BMCWEB_LOG_DEBUG << "Updated the service address";
665 },
666 ldapDbusService, ldapConfigObject, propertyInterface, "Set",
667 ldapConfigInterface, "LDAPServerURI",
668 std::variant<std::string>(serviceAddressList.front()));
669 }
670 /**
671 * @brief updates the LDAP Bind DN and updates the
672 json response with the new value.
673 * @param username name of the user which needs to be updated.
674 * @param asyncResp pointer to the JSON response
675 * @param ldapServerElementName Type of LDAP
676 server(openLDAP/ActiveDirectory)
677 */
678
679 void handleUserNamePatch(const std::string& username,
680 const std::shared_ptr<AsyncResp>& asyncResp,
681 const std::string& ldapServerElementName,
682 const std::string& ldapConfigObject)
683 {
684 crow::connections::systemBus->async_method_call(
685 [asyncResp, username,
686 ldapServerElementName](const boost::system::error_code ec) {
687 if (ec)
688 {
689 BMCWEB_LOG_DEBUG
690 << "Error occured in updating the username";
691 messages::internalError(asyncResp->res);
692 return;
693 }
694 asyncResp->res.jsonValue[ldapServerElementName]
695 ["Authentication"]["Username"] =
696 username;
697 BMCWEB_LOG_DEBUG << "Updated the username";
698 },
699 ldapDbusService, ldapConfigObject, propertyInterface, "Set",
700 ldapConfigInterface, "LDAPBindDN",
701 std::variant<std::string>(username));
702 }
703
704 /**
705 * @brief updates the LDAP password
706 * @param password : ldap password which needs to be updated.
707 * @param asyncResp pointer to the JSON response
708 * @param ldapServerElementName Type of LDAP
709 * server(openLDAP/ActiveDirectory)
710 */
711
712 void handlePasswordPatch(const std::string& password,
713 const std::shared_ptr<AsyncResp>& asyncResp,
714 const std::string& ldapServerElementName,
715 const std::string& ldapConfigObject)
716 {
717 crow::connections::systemBus->async_method_call(
718 [asyncResp, password,
719 ldapServerElementName](const boost::system::error_code ec) {
720 if (ec)
721 {
722 BMCWEB_LOG_DEBUG
723 << "Error occured in updating the password";
724 messages::internalError(asyncResp->res);
725 return;
726 }
727 asyncResp->res.jsonValue[ldapServerElementName]
728 ["Authentication"]["Password"] = "";
729 BMCWEB_LOG_DEBUG << "Updated the password";
730 },
731 ldapDbusService, ldapConfigObject, propertyInterface, "Set",
732 ldapConfigInterface, "LDAPBindDNPassword",
733 std::variant<std::string>(password));
734 }
735
736 /**
737 * @brief updates the LDAP BaseDN and updates the
738 json response with the new value.
739 * @param baseDNList baseDN list which needs to be updated.
740 * @param asyncResp pointer to the JSON response
741 * @param ldapServerElementName Type of LDAP
742 server(openLDAP/ActiveDirectory)
743 */
744
745 void handleBaseDNPatch(const std::vector<std::string>& baseDNList,
746 const std::shared_ptr<AsyncResp>& asyncResp,
747 const std::string& ldapServerElementName,
748 const std::string& ldapConfigObject)
749 {
750 crow::connections::systemBus->async_method_call(
751 [asyncResp, baseDNList,
752 ldapServerElementName](const boost::system::error_code ec) {
753 if (ec)
754 {
755 BMCWEB_LOG_DEBUG << "Error Occured in Updating the base DN";
756 messages::internalError(asyncResp->res);
757 return;
758 }
759 auto& serverTypeJson =
760 asyncResp->res.jsonValue[ldapServerElementName];
761 auto& searchSettingsJson =
762 serverTypeJson["LDAPService"]["SearchSettings"];
763 std::vector<std::string> modifiedBaseDNList = {
764 baseDNList.front()};
765 searchSettingsJson["BaseDistinguishedNames"] =
766 modifiedBaseDNList;
767 if (baseDNList.size() > 1)
768 {
769 messages::propertyValueModified(asyncResp->res,
770 "BaseDistinguishedNames",
771 baseDNList.front());
772 }
773 BMCWEB_LOG_DEBUG << "Updated the base DN";
774 },
775 ldapDbusService, ldapConfigObject, propertyInterface, "Set",
776 ldapConfigInterface, "LDAPBaseDN",
777 std::variant<std::string>(baseDNList.front()));
778 }
779 /**
780 * @brief updates the LDAP user name attribute and updates the
781 json response with the new value.
782 * @param userNameAttribute attribute to be updated.
783 * @param asyncResp pointer to the JSON response
784 * @param ldapServerElementName Type of LDAP
785 server(openLDAP/ActiveDirectory)
786 */
787
788 void handleUserNameAttrPatch(const std::string& userNameAttribute,
789 const std::shared_ptr<AsyncResp>& asyncResp,
790 const std::string& ldapServerElementName,
791 const std::string& ldapConfigObject)
792 {
793 crow::connections::systemBus->async_method_call(
794 [asyncResp, userNameAttribute,
795 ldapServerElementName](const boost::system::error_code ec) {
796 if (ec)
797 {
798 BMCWEB_LOG_DEBUG << "Error Occured in Updating the "
799 "username attribute";
800 messages::internalError(asyncResp->res);
801 return;
802 }
803 auto& serverTypeJson =
804 asyncResp->res.jsonValue[ldapServerElementName];
805 auto& searchSettingsJson =
806 serverTypeJson["LDAPService"]["SearchSettings"];
807 searchSettingsJson["UsernameAttribute"] = userNameAttribute;
808 BMCWEB_LOG_DEBUG << "Updated the user name attr.";
809 },
810 ldapDbusService, ldapConfigObject, propertyInterface, "Set",
811 ldapConfigInterface, "UserNameAttribute",
812 std::variant<std::string>(userNameAttribute));
813 }
814 /**
815 * @brief updates the LDAP group attribute and updates the
816 json response with the new value.
817 * @param groupsAttribute attribute to be updated.
818 * @param asyncResp pointer to the JSON response
819 * @param ldapServerElementName Type of LDAP
820 server(openLDAP/ActiveDirectory)
821 */
822
823 void handleGroupNameAttrPatch(const std::string& groupsAttribute,
824 const std::shared_ptr<AsyncResp>& asyncResp,
825 const std::string& ldapServerElementName,
826 const std::string& ldapConfigObject)
827 {
828 crow::connections::systemBus->async_method_call(
829 [asyncResp, groupsAttribute,
830 ldapServerElementName](const boost::system::error_code ec) {
831 if (ec)
832 {
833 BMCWEB_LOG_DEBUG << "Error Occured in Updating the "
834 "groupname attribute";
835 messages::internalError(asyncResp->res);
836 return;
837 }
838 auto& serverTypeJson =
839 asyncResp->res.jsonValue[ldapServerElementName];
840 auto& searchSettingsJson =
841 serverTypeJson["LDAPService"]["SearchSettings"];
842 searchSettingsJson["GroupsAttribute"] = groupsAttribute;
843 BMCWEB_LOG_DEBUG << "Updated the groupname attr";
844 },
845 ldapDbusService, ldapConfigObject, propertyInterface, "Set",
846 ldapConfigInterface, "GroupNameAttribute",
847 std::variant<std::string>(groupsAttribute));
848 }
849 /**
850 * @brief updates the LDAP service enable and updates the
851 json response with the new value.
852 * @param input JSON data.
853 * @param asyncResp pointer to the JSON response
854 * @param ldapServerElementName Type of LDAP
855 server(openLDAP/ActiveDirectory)
856 */
857
858 void handleServiceEnablePatch(bool serviceEnabled,
859 const std::shared_ptr<AsyncResp>& asyncResp,
860 const std::string& ldapServerElementName,
861 const std::string& ldapConfigObject)
862 {
863 crow::connections::systemBus->async_method_call(
864 [asyncResp, serviceEnabled,
865 ldapServerElementName](const boost::system::error_code ec) {
866 if (ec)
867 {
868 BMCWEB_LOG_DEBUG
869 << "Error Occured in Updating the service enable";
870 messages::internalError(asyncResp->res);
871 return;
872 }
873 asyncResp->res
874 .jsonValue[ldapServerElementName]["ServiceEnabled"] =
875 serviceEnabled;
876 BMCWEB_LOG_DEBUG << "Updated Service enable = "
877 << serviceEnabled;
878 },
879 ldapDbusService, ldapConfigObject, propertyInterface, "Set",
880 ldapEnableInterface, "Enabled", std::variant<bool>(serviceEnabled));
881 }
882
Zbigniew Kurzynski78158632019-11-05 12:57:37 +0100883 void handleAuthMethodsPatch(nlohmann::json& input,
884 const std::shared_ptr<AsyncResp>& asyncResp)
885 {
886 std::optional<bool> basicAuth;
887 std::optional<bool> cookie;
888 std::optional<bool> sessionToken;
889 std::optional<bool> xToken;
890
891 if (!json_util::readJson(input, asyncResp->res, "BasicAuth", basicAuth,
892 "Cookie", cookie, "SessionToken", sessionToken,
893 "XToken", xToken))
894 {
895 BMCWEB_LOG_ERROR << "Cannot read values from AuthMethod tag";
896 return;
897 }
898
899 // Make a copy of methods configuration
900 crow::persistent_data::AuthConfigMethods authMethodsConfig =
901 crow::persistent_data::SessionStore::getInstance()
902 .getAuthMethodsConfig();
903
904 if (basicAuth)
905 {
906 authMethodsConfig.basic = *basicAuth;
907 }
908
909 if (cookie)
910 {
911 authMethodsConfig.cookie = *cookie;
912 }
913
914 if (sessionToken)
915 {
916 authMethodsConfig.sessionToken = *sessionToken;
917 }
918
919 if (xToken)
920 {
921 authMethodsConfig.xtoken = *xToken;
922 }
923
924 if (!authMethodsConfig.basic && !authMethodsConfig.cookie &&
925 !authMethodsConfig.sessionToken && !authMethodsConfig.xtoken)
926 {
927 // Do not allow user to disable everything
928 messages::actionNotSupported(asyncResp->res,
929 "of disabling all available methods");
930 return;
931 }
932
933 crow::persistent_data::SessionStore::getInstance()
934 .updateAuthMethodsConfig(authMethodsConfig);
935 // Save configuration immediately
936 app.template getMiddleware<crow::persistent_data::Middleware>()
937 .writeData();
938
939 messages::success(asyncResp->res);
940 }
941
Ratan Gupta8a07d282019-03-16 08:33:47 +0530942 /**
943 * @brief Get the required values from the given JSON, validates the
944 * value and create the LDAP config object.
945 * @param input JSON data
946 * @param asyncResp pointer to the JSON response
947 * @param serverType Type of LDAP server(openLDAP/ActiveDirectory)
948 */
949
950 void handleLDAPPatch(nlohmann::json& input,
951 const std::shared_ptr<AsyncResp>& asyncResp,
952 const crow::Request& req,
953 const std::vector<std::string>& params,
954 const std::string& serverType)
955 {
Ratan Guptaeb2bbe52019-04-22 14:27:01 +0530956 std::string dbusObjectPath;
957 if (serverType == "ActiveDirectory")
958 {
959 dbusObjectPath = ADConfigObject;
960 }
961 else if (serverType == "LDAP")
962 {
963 dbusObjectPath = ldapConfigObject;
964 }
965
Ratan Gupta8a07d282019-03-16 08:33:47 +0530966 std::optional<nlohmann::json> authentication;
967 std::optional<nlohmann::json> ldapService;
968 std::optional<std::string> accountProviderType;
969 std::optional<std::vector<std::string>> serviceAddressList;
970 std::optional<bool> serviceEnabled;
971 std::optional<std::vector<std::string>> baseDNList;
972 std::optional<std::string> userNameAttribute;
973 std::optional<std::string> groupsAttribute;
974 std::optional<std::string> userName;
975 std::optional<std::string> password;
Ratan Gupta06785242019-07-26 22:30:16 +0530976 std::optional<std::vector<nlohmann::json>> remoteRoleMapData;
Ratan Gupta8a07d282019-03-16 08:33:47 +0530977
978 if (!json_util::readJson(input, asyncResp->res, "Authentication",
979 authentication, "LDAPService", ldapService,
980 "ServiceAddresses", serviceAddressList,
981 "AccountProviderType", accountProviderType,
Ratan Gupta06785242019-07-26 22:30:16 +0530982 "ServiceEnabled", serviceEnabled,
983 "RemoteRoleMapping", remoteRoleMapData))
Ratan Gupta8a07d282019-03-16 08:33:47 +0530984 {
985 return;
986 }
987
988 if (authentication)
989 {
990 parseLDAPAuthenticationJson(*authentication, asyncResp, userName,
991 password);
992 }
993 if (ldapService)
994 {
995 parseLDAPServiceJson(*ldapService, asyncResp, baseDNList,
996 userNameAttribute, groupsAttribute);
997 }
998 if (accountProviderType)
999 {
1000 messages::propertyNotWritable(asyncResp->res,
1001 "AccountProviderType");
1002 }
1003 if (serviceAddressList)
1004 {
1005 if ((*serviceAddressList).size() == 0)
1006 {
1007 messages::propertyValueNotInList(asyncResp->res, "[]",
1008 "ServiceAddress");
1009 return;
1010 }
1011 }
1012 if (baseDNList)
1013 {
1014 if ((*baseDNList).size() == 0)
1015 {
1016 messages::propertyValueNotInList(asyncResp->res, "[]",
1017 "BaseDistinguishedNames");
1018 return;
1019 }
1020 }
1021
1022 // nothing to update, then return
1023 if (!userName && !password && !serviceAddressList && !baseDNList &&
Ratan Gupta06785242019-07-26 22:30:16 +05301024 !userNameAttribute && !groupsAttribute && !serviceEnabled &&
1025 !remoteRoleMapData)
Ratan Gupta8a07d282019-03-16 08:33:47 +05301026 {
1027 return;
1028 }
1029
1030 // Get the existing resource first then keep modifying
1031 // whenever any property gets updated.
Ratan Guptaab828d72019-04-22 14:18:33 +05301032 getLDAPConfigData(serverType, [this, asyncResp, userName, password,
1033 baseDNList, userNameAttribute,
1034 groupsAttribute, accountProviderType,
Ratan Guptaeb2bbe52019-04-22 14:27:01 +05301035 serviceAddressList, serviceEnabled,
Ratan Gupta06785242019-07-26 22:30:16 +05301036 dbusObjectPath, remoteRoleMapData](
Ratan Guptaab828d72019-04-22 14:18:33 +05301037 bool success, LDAPConfigData confData,
1038 const std::string& serverType) {
1039 if (!success)
1040 {
1041 messages::internalError(asyncResp->res);
1042 return;
1043 }
1044 parseLDAPConfigData(asyncResp->res.jsonValue, confData, serverType);
1045 if (confData.serviceEnabled)
1046 {
1047 // Disable the service first and update the rest of
1048 // the properties.
1049 handleServiceEnablePatch(false, asyncResp, serverType,
Ratan Guptaeb2bbe52019-04-22 14:27:01 +05301050 dbusObjectPath);
Ratan Guptaab828d72019-04-22 14:18:33 +05301051 }
Ratan Gupta8a07d282019-03-16 08:33:47 +05301052
Ratan Guptaab828d72019-04-22 14:18:33 +05301053 if (serviceAddressList)
1054 {
1055 handleServiceAddressPatch(*serviceAddressList, asyncResp,
Ratan Guptaeb2bbe52019-04-22 14:27:01 +05301056 serverType, dbusObjectPath);
Ratan Guptaab828d72019-04-22 14:18:33 +05301057 }
1058 if (userName)
1059 {
1060 handleUserNamePatch(*userName, asyncResp, serverType,
Ratan Guptaeb2bbe52019-04-22 14:27:01 +05301061 dbusObjectPath);
Ratan Guptaab828d72019-04-22 14:18:33 +05301062 }
1063 if (password)
1064 {
1065 handlePasswordPatch(*password, asyncResp, serverType,
Ratan Guptaeb2bbe52019-04-22 14:27:01 +05301066 dbusObjectPath);
Ratan Guptaab828d72019-04-22 14:18:33 +05301067 }
Ratan Gupta8a07d282019-03-16 08:33:47 +05301068
Ratan Guptaab828d72019-04-22 14:18:33 +05301069 if (baseDNList)
1070 {
1071 handleBaseDNPatch(*baseDNList, asyncResp, serverType,
Ratan Guptaeb2bbe52019-04-22 14:27:01 +05301072 dbusObjectPath);
Ratan Guptaab828d72019-04-22 14:18:33 +05301073 }
1074 if (userNameAttribute)
1075 {
1076 handleUserNameAttrPatch(*userNameAttribute, asyncResp,
Ratan Guptaeb2bbe52019-04-22 14:27:01 +05301077 serverType, dbusObjectPath);
Ratan Guptaab828d72019-04-22 14:18:33 +05301078 }
1079 if (groupsAttribute)
1080 {
1081 handleGroupNameAttrPatch(*groupsAttribute, asyncResp,
Ratan Guptaeb2bbe52019-04-22 14:27:01 +05301082 serverType, dbusObjectPath);
Ratan Guptaab828d72019-04-22 14:18:33 +05301083 }
1084 if (serviceEnabled)
1085 {
1086 // if user has given the value as true then enable
1087 // the service. if user has given false then no-op
1088 // as service is already stopped.
1089 if (*serviceEnabled)
Ratan Gupta8a07d282019-03-16 08:33:47 +05301090 {
Ratan Guptaab828d72019-04-22 14:18:33 +05301091 handleServiceEnablePatch(*serviceEnabled, asyncResp,
Ratan Guptaeb2bbe52019-04-22 14:27:01 +05301092 serverType, dbusObjectPath);
Ratan Gupta8a07d282019-03-16 08:33:47 +05301093 }
Ratan Guptaab828d72019-04-22 14:18:33 +05301094 }
1095 else
1096 {
1097 // if user has not given the service enabled value
1098 // then revert it to the same state as it was
1099 // before.
1100 handleServiceEnablePatch(confData.serviceEnabled, asyncResp,
Ratan Guptaeb2bbe52019-04-22 14:27:01 +05301101 serverType, dbusObjectPath);
Ratan Guptaab828d72019-04-22 14:18:33 +05301102 }
Ratan Gupta06785242019-07-26 22:30:16 +05301103
1104 if (remoteRoleMapData)
1105 {
1106 std::vector<nlohmann::json> remoteRoleMap =
1107 std::move(*remoteRoleMapData);
1108
1109 handleRoleMapPatch(asyncResp, confData.groupRoleList,
1110 serverType, remoteRoleMap);
1111 }
Ratan Guptaab828d72019-04-22 14:18:33 +05301112 });
Ratan Gupta8a07d282019-03-16 08:33:47 +05301113 }
Ed Tanousd4b54432019-07-17 22:51:55 +00001114
Ed Tanous1abe55e2018-09-05 08:30:59 -07001115 void doGet(crow::Response& res, const crow::Request& req,
1116 const std::vector<std::string>& params) override
1117 {
Zbigniew Kurzynski78158632019-11-05 12:57:37 +01001118 const crow::persistent_data::AuthConfigMethods& authMethodsConfig =
1119 crow::persistent_data::SessionStore::getInstance()
1120 .getAuthMethodsConfig();
1121
AppaRao Puli3d958bb2018-12-25 12:45:54 +05301122 auto asyncResp = std::make_shared<AsyncResp>(res);
1123 res.jsonValue = {
1124 {"@odata.context", "/redfish/v1/"
1125 "$metadata#AccountService.AccountService"},
1126 {"@odata.id", "/redfish/v1/AccountService"},
1127 {"@odata.type", "#AccountService."
Marri Devender Rao37cce912019-02-20 01:05:22 -06001128 "v1_4_0.AccountService"},
AppaRao Puli3d958bb2018-12-25 12:45:54 +05301129 {"Id", "AccountService"},
1130 {"Name", "Account Service"},
1131 {"Description", "Account Service"},
1132 {"ServiceEnabled", true},
AppaRao Puli343ff2e2019-03-24 00:42:13 +05301133 {"MaxPasswordLength", 20},
AppaRao Puli3d958bb2018-12-25 12:45:54 +05301134 {"Accounts",
1135 {{"@odata.id", "/redfish/v1/AccountService/Accounts"}}},
Marri Devender Rao37cce912019-02-20 01:05:22 -06001136 {"Roles", {{"@odata.id", "/redfish/v1/AccountService/Roles"}}},
Zbigniew Kurzynski78158632019-11-05 12:57:37 +01001137 {"Oem",
1138 {{"OpenBMC",
1139 {{"@odata.type", "#OemAccountService.v1_0_0.AccountService"},
1140 {"AuthMethods",
1141 {
1142 {"BasicAuth", authMethodsConfig.basic},
1143 {"SessionToken", authMethodsConfig.sessionToken},
1144 {"XToken", authMethodsConfig.xtoken},
1145 {"Cookie", authMethodsConfig.cookie},
1146 }}}}}},
Marri Devender Rao37cce912019-02-20 01:05:22 -06001147 {"LDAP",
1148 {{"Certificates",
1149 {{"@odata.id",
1150 "/redfish/v1/AccountService/LDAP/Certificates"}}}}}};
AppaRao Puli3d958bb2018-12-25 12:45:54 +05301151 crow::connections::systemBus->async_method_call(
1152 [asyncResp](
1153 const boost::system::error_code ec,
1154 const std::vector<std::pair<
Ed Tanousabf2add2019-01-22 16:40:12 -08001155 std::string, std::variant<uint32_t, uint16_t, uint8_t>>>&
AppaRao Puli3d958bb2018-12-25 12:45:54 +05301156 propertiesList) {
1157 if (ec)
1158 {
1159 messages::internalError(asyncResp->res);
1160 return;
1161 }
1162 BMCWEB_LOG_DEBUG << "Got " << propertiesList.size()
1163 << "properties for AccountService";
1164 for (const std::pair<std::string,
Ed Tanousabf2add2019-01-22 16:40:12 -08001165 std::variant<uint32_t, uint16_t, uint8_t>>&
AppaRao Puli3d958bb2018-12-25 12:45:54 +05301166 property : propertiesList)
1167 {
1168 if (property.first == "MinPasswordLength")
1169 {
1170 const uint8_t* value =
Ed Tanousabf2add2019-01-22 16:40:12 -08001171 std::get_if<uint8_t>(&property.second);
AppaRao Puli3d958bb2018-12-25 12:45:54 +05301172 if (value != nullptr)
1173 {
1174 asyncResp->res.jsonValue["MinPasswordLength"] =
1175 *value;
1176 }
1177 }
1178 if (property.first == "AccountUnlockTimeout")
1179 {
1180 const uint32_t* value =
Ed Tanousabf2add2019-01-22 16:40:12 -08001181 std::get_if<uint32_t>(&property.second);
AppaRao Puli3d958bb2018-12-25 12:45:54 +05301182 if (value != nullptr)
1183 {
1184 asyncResp->res.jsonValue["AccountLockoutDuration"] =
1185 *value;
1186 }
1187 }
1188 if (property.first == "MaxLoginAttemptBeforeLockout")
1189 {
1190 const uint16_t* value =
Ed Tanousabf2add2019-01-22 16:40:12 -08001191 std::get_if<uint16_t>(&property.second);
AppaRao Puli3d958bb2018-12-25 12:45:54 +05301192 if (value != nullptr)
1193 {
1194 asyncResp->res
1195 .jsonValue["AccountLockoutThreshold"] = *value;
1196 }
1197 }
1198 }
1199 },
1200 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
1201 "org.freedesktop.DBus.Properties", "GetAll",
1202 "xyz.openbmc_project.User.AccountPolicy");
Ratan Gupta6973a582018-12-13 18:25:44 +05301203
Ratan Guptaab828d72019-04-22 14:18:33 +05301204 auto callback = [asyncResp](bool success, LDAPConfigData& confData,
1205 const std::string& ldapType) {
1206 parseLDAPConfigData(asyncResp->res.jsonValue, confData, ldapType);
1207 };
1208
1209 getLDAPConfigData("LDAP", callback);
1210 getLDAPConfigData("ActiveDirectory", callback);
AppaRao Puli3d958bb2018-12-25 12:45:54 +05301211 }
Ratan Gupta6973a582018-12-13 18:25:44 +05301212
AppaRao Puli3d958bb2018-12-25 12:45:54 +05301213 void doPatch(crow::Response& res, const crow::Request& req,
1214 const std::vector<std::string>& params) override
1215 {
1216 auto asyncResp = std::make_shared<AsyncResp>(res);
1217
1218 std::optional<uint32_t> unlockTimeout;
1219 std::optional<uint16_t> lockoutThreshold;
Ratan Gupta19fb6e72019-03-04 13:30:50 +05301220 std::optional<uint16_t> minPasswordLength;
1221 std::optional<uint16_t> maxPasswordLength;
Ratan Gupta8a07d282019-03-16 08:33:47 +05301222 std::optional<nlohmann::json> ldapObject;
Ratan Guptaeb2bbe52019-04-22 14:27:01 +05301223 std::optional<nlohmann::json> activeDirectoryObject;
Zbigniew Kurzynski78158632019-11-05 12:57:37 +01001224 std::optional<nlohmann::json> oemObject;
Ratan Gupta19fb6e72019-03-04 13:30:50 +05301225
Zbigniew Kurzynski78158632019-11-05 12:57:37 +01001226 if (!json_util::readJson(
1227 req, res, "AccountLockoutDuration", unlockTimeout,
1228 "AccountLockoutThreshold", lockoutThreshold,
1229 "MaxPasswordLength", maxPasswordLength, "MinPasswordLength",
1230 minPasswordLength, "LDAP", ldapObject, "ActiveDirectory",
1231 activeDirectoryObject, "Oem", oemObject))
AppaRao Puli3d958bb2018-12-25 12:45:54 +05301232 {
1233 return;
1234 }
Ratan Gupta19fb6e72019-03-04 13:30:50 +05301235
1236 if (minPasswordLength)
1237 {
1238 messages::propertyNotWritable(asyncResp->res, "MinPasswordLength");
1239 }
1240
1241 if (maxPasswordLength)
1242 {
1243 messages::propertyNotWritable(asyncResp->res, "MaxPasswordLength");
1244 }
1245
Ratan Gupta8a07d282019-03-16 08:33:47 +05301246 if (ldapObject)
1247 {
1248 handleLDAPPatch(*ldapObject, asyncResp, req, params, "LDAP");
1249 }
1250
Zbigniew Kurzynski78158632019-11-05 12:57:37 +01001251 if (std::optional<nlohmann::json> oemOpenBMCObject;
1252 oemObject &&
1253 json_util::readJson(*oemObject, res, "OpenBMC", oemOpenBMCObject))
1254 {
1255 if (std::optional<nlohmann::json> authMethodsObject;
1256 oemOpenBMCObject &&
1257 json_util::readJson(*oemOpenBMCObject, res, "AuthMethods",
1258 authMethodsObject))
1259 {
1260 if (authMethodsObject)
1261 {
1262 handleAuthMethodsPatch(*authMethodsObject, asyncResp);
1263 }
1264 }
1265 }
1266
Ratan Guptaeb2bbe52019-04-22 14:27:01 +05301267 if (activeDirectoryObject)
1268 {
1269 handleLDAPPatch(*activeDirectoryObject, asyncResp, req, params,
1270 "ActiveDirectory");
1271 }
1272
AppaRao Puli3d958bb2018-12-25 12:45:54 +05301273 if (unlockTimeout)
1274 {
1275 crow::connections::systemBus->async_method_call(
1276 [asyncResp](const boost::system::error_code ec) {
1277 if (ec)
1278 {
1279 messages::internalError(asyncResp->res);
1280 return;
1281 }
Ratan Guptaadd61332019-02-13 20:49:16 +05301282 messages::success(asyncResp->res);
AppaRao Puli3d958bb2018-12-25 12:45:54 +05301283 },
1284 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
1285 "org.freedesktop.DBus.Properties", "Set",
1286 "xyz.openbmc_project.User.AccountPolicy",
Ed Tanousabf2add2019-01-22 16:40:12 -08001287 "AccountUnlockTimeout", std::variant<uint32_t>(*unlockTimeout));
AppaRao Puli3d958bb2018-12-25 12:45:54 +05301288 }
1289 if (lockoutThreshold)
1290 {
1291 crow::connections::systemBus->async_method_call(
1292 [asyncResp](const boost::system::error_code ec) {
1293 if (ec)
1294 {
1295 messages::internalError(asyncResp->res);
1296 return;
1297 }
Ratan Guptaadd61332019-02-13 20:49:16 +05301298 messages::success(asyncResp->res);
AppaRao Puli3d958bb2018-12-25 12:45:54 +05301299 },
1300 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
1301 "org.freedesktop.DBus.Properties", "Set",
1302 "xyz.openbmc_project.User.AccountPolicy",
1303 "MaxLoginAttemptBeforeLockout",
Ed Tanousabf2add2019-01-22 16:40:12 -08001304 std::variant<uint16_t>(*lockoutThreshold));
AppaRao Puli3d958bb2018-12-25 12:45:54 +05301305 }
Ed Tanous1abe55e2018-09-05 08:30:59 -07001306 }
Zbigniew Kurzynski78158632019-11-05 12:57:37 +01001307
1308 CrowApp& app;
Lewanczyk, Dawid88d16c92018-02-02 14:51:09 +01001309};
Tanousf00032d2018-11-05 01:18:10 -03001310
Ed Tanousb9b2e0b2018-09-13 13:47:50 -07001311class AccountsCollection : public Node
1312{
1313 public:
1314 AccountsCollection(CrowApp& app) :
1315 Node(app, "/redfish/v1/AccountService/Accounts/")
1316 {
Ed Tanousb9b2e0b2018-09-13 13:47:50 -07001317 entityPrivileges = {
1318 {boost::beast::http::verb::get,
1319 {{"ConfigureUsers"}, {"ConfigureManager"}}},
1320 {boost::beast::http::verb::head, {{"Login"}}},
1321 {boost::beast::http::verb::patch, {{"ConfigureUsers"}}},
1322 {boost::beast::http::verb::put, {{"ConfigureUsers"}}},
1323 {boost::beast::http::verb::delete_, {{"ConfigureUsers"}}},
1324 {boost::beast::http::verb::post, {{"ConfigureUsers"}}}};
1325 }
1326
1327 private:
1328 void doGet(crow::Response& res, const crow::Request& req,
1329 const std::vector<std::string>& params) override
1330 {
Ed Tanousb9b2e0b2018-09-13 13:47:50 -07001331 auto asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous0f74e642018-11-12 15:17:05 -08001332 res.jsonValue = {{"@odata.context",
1333 "/redfish/v1/"
1334 "$metadata#ManagerAccountCollection."
1335 "ManagerAccountCollection"},
1336 {"@odata.id", "/redfish/v1/AccountService/Accounts"},
1337 {"@odata.type", "#ManagerAccountCollection."
1338 "ManagerAccountCollection"},
1339 {"Name", "Accounts Collection"},
1340 {"Description", "BMC User Accounts"}};
1341
Ed Tanousb9b2e0b2018-09-13 13:47:50 -07001342 crow::connections::systemBus->async_method_call(
1343 [asyncResp](const boost::system::error_code ec,
1344 const ManagedObjectType& users) {
1345 if (ec)
1346 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001347 messages::internalError(asyncResp->res);
Ed Tanousb9b2e0b2018-09-13 13:47:50 -07001348 return;
1349 }
1350
1351 nlohmann::json& memberArray =
1352 asyncResp->res.jsonValue["Members"];
1353 memberArray = nlohmann::json::array();
1354
1355 asyncResp->res.jsonValue["Members@odata.count"] = users.size();
1356 for (auto& user : users)
1357 {
1358 const std::string& path =
1359 static_cast<const std::string&>(user.first);
1360 std::size_t lastIndex = path.rfind("/");
1361 if (lastIndex == std::string::npos)
1362 {
1363 lastIndex = 0;
1364 }
1365 else
1366 {
1367 lastIndex += 1;
1368 }
1369 memberArray.push_back(
1370 {{"@odata.id", "/redfish/v1/AccountService/Accounts/" +
1371 path.substr(lastIndex)}});
1372 }
1373 },
1374 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
1375 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
1376 }
Ed Tanous04ae99e2018-09-20 15:54:36 -07001377 void doPost(crow::Response& res, const crow::Request& req,
1378 const std::vector<std::string>& params) override
1379 {
1380 auto asyncResp = std::make_shared<AsyncResp>(res);
1381
Ed Tanous9712f8a2018-09-21 13:38:49 -07001382 std::string username;
1383 std::string password;
Ed Tanousa24526d2018-12-10 15:17:59 -08001384 std::optional<std::string> roleId("User");
1385 std::optional<bool> enabled = true;
Ed Tanous9712f8a2018-09-21 13:38:49 -07001386 if (!json_util::readJson(req, res, "UserName", username, "Password",
1387 password, "RoleId", roleId, "Enabled",
1388 enabled))
Ed Tanous04ae99e2018-09-20 15:54:36 -07001389 {
1390 return;
1391 }
1392
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -06001393 std::string priv = getPrivilegeFromRoleId(*roleId);
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301394 if (priv.empty())
Ed Tanous04ae99e2018-09-20 15:54:36 -07001395 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001396 messages::propertyValueNotInList(asyncResp->res, *roleId, "RoleId");
Ed Tanous04ae99e2018-09-20 15:54:36 -07001397 return;
1398 }
Ed Tanous9712f8a2018-09-21 13:38:49 -07001399 roleId = priv;
Ed Tanous04ae99e2018-09-20 15:54:36 -07001400
Ayushi Smriti599c71d2019-08-23 17:43:18 +00001401 // Reading AllGroups property
Ed Tanous04ae99e2018-09-20 15:54:36 -07001402 crow::connections::systemBus->async_method_call(
Ayushi Smriti599c71d2019-08-23 17:43:18 +00001403 [asyncResp, username, password{std::move(password)}, roleId,
1404 enabled](const boost::system::error_code ec,
1405 const std::variant<std::vector<std::string>>& allGroups) {
Ed Tanous04ae99e2018-09-20 15:54:36 -07001406 if (ec)
1407 {
Ayushi Smriti599c71d2019-08-23 17:43:18 +00001408 BMCWEB_LOG_DEBUG << "ERROR with async_method_call";
1409 messages::internalError(asyncResp->res);
Ed Tanous04ae99e2018-09-20 15:54:36 -07001410 return;
1411 }
1412
Ayushi Smriti599c71d2019-08-23 17:43:18 +00001413 const std::vector<std::string>* allGroupsList =
1414 std::get_if<std::vector<std::string>>(&allGroups);
1415
1416 if (allGroupsList == nullptr || allGroupsList->empty())
Ed Tanous04ae99e2018-09-20 15:54:36 -07001417 {
Ayushi Smriti599c71d2019-08-23 17:43:18 +00001418 messages::internalError(asyncResp->res);
Ed Tanous04ae99e2018-09-20 15:54:36 -07001419 return;
1420 }
1421
Ayushi Smriti599c71d2019-08-23 17:43:18 +00001422 crow::connections::systemBus->async_method_call(
1423 [asyncResp, username, password{std::move(password)}](
anil kumar appana0d4197e2019-06-13 15:06:23 +00001424 const boost::system::error_code ec,
1425 sdbusplus::message::message& m) {
Ayushi Smriti599c71d2019-08-23 17:43:18 +00001426 if (ec)
1427 {
anil kumar appana0d4197e2019-06-13 15:06:23 +00001428 userErrorMessageHandler(m.get_error(), asyncResp,
1429 username, "");
Ayushi Smriti599c71d2019-08-23 17:43:18 +00001430 return;
1431 }
1432
jayaprakash Mutyala66b5ca72019-08-07 20:26:37 +00001433 if (pamUpdatePassword(username, password) !=
1434 PAM_SUCCESS)
Ayushi Smriti599c71d2019-08-23 17:43:18 +00001435 {
1436 // At this point we have a user that's been created,
1437 // but the password set failed.Something is wrong,
1438 // so delete the user that we've already created
1439 crow::connections::systemBus->async_method_call(
anil kumar appana0d4197e2019-06-13 15:06:23 +00001440 [asyncResp,
1441 password](const boost::system::error_code ec) {
Ayushi Smriti599c71d2019-08-23 17:43:18 +00001442 if (ec)
1443 {
1444 messages::internalError(asyncResp->res);
1445 return;
1446 }
1447
anil kumar appana0d4197e2019-06-13 15:06:23 +00001448 // If password is invalid
1449 messages::propertyValueFormatError(
1450 asyncResp->res, password, "Password");
Ayushi Smriti599c71d2019-08-23 17:43:18 +00001451 },
1452 "xyz.openbmc_project.User.Manager",
1453 "/xyz/openbmc_project/user/" + username,
1454 "xyz.openbmc_project.Object.Delete", "Delete");
1455
1456 BMCWEB_LOG_ERROR << "pamUpdatePassword Failed";
1457 return;
1458 }
1459
1460 messages::created(asyncResp->res);
1461 asyncResp->res.addHeader(
1462 "Location",
1463 "/redfish/v1/AccountService/Accounts/" + username);
1464 },
1465 "xyz.openbmc_project.User.Manager",
1466 "/xyz/openbmc_project/user",
1467 "xyz.openbmc_project.User.Manager", "CreateUser", username,
1468 *allGroupsList, *roleId, *enabled);
Ed Tanous04ae99e2018-09-20 15:54:36 -07001469 },
1470 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
Ayushi Smriti599c71d2019-08-23 17:43:18 +00001471 "org.freedesktop.DBus.Properties", "Get",
1472 "xyz.openbmc_project.User.Manager", "AllGroups");
Ed Tanous04ae99e2018-09-20 15:54:36 -07001473 }
Ed Tanousb9b2e0b2018-09-13 13:47:50 -07001474};
1475
1476class ManagerAccount : public Node
1477{
1478 public:
1479 ManagerAccount(CrowApp& app) :
1480 Node(app, "/redfish/v1/AccountService/Accounts/<str>/", std::string())
1481 {
Ed Tanousb9b2e0b2018-09-13 13:47:50 -07001482 entityPrivileges = {
1483 {boost::beast::http::verb::get,
1484 {{"ConfigureUsers"}, {"ConfigureManager"}, {"ConfigureSelf"}}},
1485 {boost::beast::http::verb::head, {{"Login"}}},
1486 {boost::beast::http::verb::patch, {{"ConfigureUsers"}}},
1487 {boost::beast::http::verb::put, {{"ConfigureUsers"}}},
1488 {boost::beast::http::verb::delete_, {{"ConfigureUsers"}}},
1489 {boost::beast::http::verb::post, {{"ConfigureUsers"}}}};
1490 }
1491
1492 private:
1493 void doGet(crow::Response& res, const crow::Request& req,
1494 const std::vector<std::string>& params) override
1495 {
Ed Tanous0f74e642018-11-12 15:17:05 -08001496
Ed Tanousb9b2e0b2018-09-13 13:47:50 -07001497 auto asyncResp = std::make_shared<AsyncResp>(res);
1498
1499 if (params.size() != 1)
1500 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001501 messages::internalError(asyncResp->res);
Ed Tanousb9b2e0b2018-09-13 13:47:50 -07001502 return;
1503 }
1504
1505 crow::connections::systemBus->async_method_call(
1506 [asyncResp, accountName{std::string(params[0])}](
1507 const boost::system::error_code ec,
1508 const ManagedObjectType& users) {
1509 if (ec)
1510 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001511 messages::internalError(asyncResp->res);
Ed Tanousb9b2e0b2018-09-13 13:47:50 -07001512 return;
1513 }
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301514 auto userIt = users.begin();
Ed Tanousb9b2e0b2018-09-13 13:47:50 -07001515
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301516 for (; userIt != users.end(); userIt++)
Ed Tanousb9b2e0b2018-09-13 13:47:50 -07001517 {
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301518 if (boost::ends_with(userIt->first.str, "/" + accountName))
Ed Tanousb9b2e0b2018-09-13 13:47:50 -07001519 {
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301520 break;
Ed Tanousb9b2e0b2018-09-13 13:47:50 -07001521 }
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301522 }
1523 if (userIt == users.end())
1524 {
1525 messages::resourceNotFound(asyncResp->res, "ManagerAccount",
1526 accountName);
1527 return;
1528 }
Ayushi Smriti4e68c452019-09-04 14:37:55 +05301529
1530 asyncResp->res.jsonValue = {
1531 {"@odata.context",
1532 "/redfish/v1/$metadata#ManagerAccount.ManagerAccount"},
1533 {"@odata.type", "#ManagerAccount.v1_0_3.ManagerAccount"},
1534 {"Name", "User Account"},
1535 {"Description", "User Account"},
1536 {"Password", nullptr}};
1537
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301538 for (const auto& interface : userIt->second)
1539 {
1540 if (interface.first ==
1541 "xyz.openbmc_project.User.Attributes")
Ed Tanousb9b2e0b2018-09-13 13:47:50 -07001542 {
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301543 for (const auto& property : interface.second)
Ed Tanous65b0dc32018-09-19 16:04:03 -07001544 {
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301545 if (property.first == "UserEnabled")
Ed Tanous65b0dc32018-09-19 16:04:03 -07001546 {
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301547 const bool* userEnabled =
Ed Tanousabf2add2019-01-22 16:40:12 -08001548 std::get_if<bool>(&property.second);
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301549 if (userEnabled == nullptr)
Ed Tanous65b0dc32018-09-19 16:04:03 -07001550 {
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301551 BMCWEB_LOG_ERROR
1552 << "UserEnabled wasn't a bool";
1553 messages::internalError(asyncResp->res);
1554 return;
Ed Tanous65b0dc32018-09-19 16:04:03 -07001555 }
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301556 asyncResp->res.jsonValue["Enabled"] =
1557 *userEnabled;
1558 }
1559 else if (property.first ==
1560 "UserLockedForFailedAttempt")
1561 {
1562 const bool* userLocked =
Ed Tanousabf2add2019-01-22 16:40:12 -08001563 std::get_if<bool>(&property.second);
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301564 if (userLocked == nullptr)
1565 {
1566 BMCWEB_LOG_ERROR << "UserLockedForF"
1567 "ailedAttempt "
1568 "wasn't a bool";
1569 messages::internalError(asyncResp->res);
1570 return;
1571 }
1572 asyncResp->res.jsonValue["Locked"] =
1573 *userLocked;
Ratan Gupta24c85422019-01-30 19:41:24 +05301574 asyncResp->res.jsonValue
1575 ["Locked@Redfish.AllowableValues"] = {
Gunnar Mills4d64ce32019-03-29 16:34:56 -05001576 "false"};
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301577 }
1578 else if (property.first == "UserPrivilege")
1579 {
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -06001580 const std::string* userPrivPtr =
Ed Tanousabf2add2019-01-22 16:40:12 -08001581 std::get_if<std::string>(&property.second);
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -06001582 if (userPrivPtr == nullptr)
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301583 {
1584 BMCWEB_LOG_ERROR
1585 << "UserPrivilege wasn't a "
1586 "string";
1587 messages::internalError(asyncResp->res);
1588 return;
1589 }
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -06001590 std::string role =
1591 getRoleIdFromPrivilege(*userPrivPtr);
1592 if (role.empty())
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301593 {
1594 BMCWEB_LOG_ERROR << "Invalid user role";
1595 messages::internalError(asyncResp->res);
1596 return;
1597 }
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -06001598 asyncResp->res.jsonValue["RoleId"] = role;
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301599
1600 asyncResp->res.jsonValue["Links"]["Role"] = {
1601 {"@odata.id", "/redfish/v1/AccountService/"
1602 "Roles/" +
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -06001603 role}};
Ed Tanous65b0dc32018-09-19 16:04:03 -07001604 }
1605 }
Ed Tanousb9b2e0b2018-09-13 13:47:50 -07001606 }
1607 }
1608
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301609 asyncResp->res.jsonValue["@odata.id"] =
1610 "/redfish/v1/AccountService/Accounts/" + accountName;
1611 asyncResp->res.jsonValue["Id"] = accountName;
1612 asyncResp->res.jsonValue["UserName"] = accountName;
Ed Tanousb9b2e0b2018-09-13 13:47:50 -07001613 },
1614 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
1615 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
1616 }
Ed Tanousa8408792018-09-05 16:08:38 -07001617
1618 void doPatch(crow::Response& res, const crow::Request& req,
1619 const std::vector<std::string>& params) override
1620 {
1621 auto asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanousa8408792018-09-05 16:08:38 -07001622 if (params.size() != 1)
1623 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001624 messages::internalError(asyncResp->res);
Ed Tanousa8408792018-09-05 16:08:38 -07001625 return;
1626 }
1627
Ed Tanousa24526d2018-12-10 15:17:59 -08001628 std::optional<std::string> newUserName;
1629 std::optional<std::string> password;
1630 std::optional<bool> enabled;
1631 std::optional<std::string> roleId;
Ratan Gupta24c85422019-01-30 19:41:24 +05301632 std::optional<bool> locked;
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301633 if (!json_util::readJson(req, res, "UserName", newUserName, "Password",
Ratan Gupta24c85422019-01-30 19:41:24 +05301634 password, "RoleId", roleId, "Enabled", enabled,
1635 "Locked", locked))
Ed Tanousa8408792018-09-05 16:08:38 -07001636 {
1637 return;
1638 }
1639
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301640 const std::string& username = params[0];
Ed Tanousa8408792018-09-05 16:08:38 -07001641
jayaprakash Mutyala66b5ca72019-08-07 20:26:37 +00001642 // if user name is not provided in the patch method or if it
1643 // matches the user name in the URI, then we are treating it as updating
1644 // user properties other then username. If username provided doesn't
1645 // match the URI, then we are treating this as user rename request.
1646 if (!newUserName || (newUserName.value() == username))
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301647 {
Ratan Gupta24c85422019-01-30 19:41:24 +05301648 updateUserProperties(asyncResp, username, password, enabled, roleId,
1649 locked);
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301650 return;
1651 }
1652 else
1653 {
1654 crow::connections::systemBus->async_method_call(
1655 [this, asyncResp, username, password(std::move(password)),
1656 roleId(std::move(roleId)), enabled(std::move(enabled)),
jayaprakash Mutyala66b5ca72019-08-07 20:26:37 +00001657 newUser{std::string(*newUserName)},
1658 locked(std::move(locked))](const boost::system::error_code ec,
1659 sdbusplus::message::message& m) {
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301660 if (ec)
Ed Tanousa8408792018-09-05 16:08:38 -07001661 {
jayaprakash Mutyala66b5ca72019-08-07 20:26:37 +00001662 userErrorMessageHandler(m.get_error(), asyncResp,
1663 newUser, username);
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301664 return;
1665 }
1666
1667 updateUserProperties(asyncResp, newUser, password, enabled,
Ratan Gupta24c85422019-01-30 19:41:24 +05301668 roleId, locked);
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301669 },
1670 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
1671 "xyz.openbmc_project.User.Manager", "RenameUser", username,
1672 *newUserName);
1673 }
1674 }
1675
1676 void updateUserProperties(std::shared_ptr<AsyncResp> asyncResp,
1677 const std::string& username,
Ed Tanousa24526d2018-12-10 15:17:59 -08001678 std::optional<std::string> password,
1679 std::optional<bool> enabled,
Ratan Gupta24c85422019-01-30 19:41:24 +05301680 std::optional<std::string> roleId,
1681 std::optional<bool> locked)
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301682 {
Ratan Gupta24c85422019-01-30 19:41:24 +05301683 std::string dbusObjectPath = "/xyz/openbmc_project/user/" + username;
1684 dbus::utility::escapePathForDbus(dbusObjectPath);
1685
Ratan Gupta22c33712019-05-03 21:50:28 +05301686 dbus::utility::checkDbusPathExists(
Ratan Gupta24c85422019-01-30 19:41:24 +05301687 dbusObjectPath,
1688 [dbusObjectPath(std::move(dbusObjectPath)), username,
1689 password(std::move(password)), roleId(std::move(roleId)),
1690 enabled(std::move(enabled)), locked(std::move(locked)),
1691 asyncResp{std::move(asyncResp)}](int rc) {
1692 if (!rc)
1693 {
jayaprakash Mutyala66b5ca72019-08-07 20:26:37 +00001694 messages::resourceNotFound(
1695 asyncResp->res, "#ManagerAccount.v1_0_3.ManagerAccount",
1696 username);
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301697 return;
Ratan Gupta24c85422019-01-30 19:41:24 +05301698 }
jayaprakash Mutyala66b5ca72019-08-07 20:26:37 +00001699
1700 if (password)
1701 {
1702 int retval = pamUpdatePassword(username, *password);
1703
1704 if (retval == PAM_USER_UNKNOWN)
1705 {
1706 messages::resourceNotFound(
1707 asyncResp->res,
1708 "#ManagerAccount.v1_0_3.ManagerAccount", username);
1709 }
1710 else if (retval == PAM_AUTHTOK_ERR)
1711 {
1712 // If password is invalid
1713 messages::propertyValueFormatError(
1714 asyncResp->res, *password, "Password");
1715 BMCWEB_LOG_ERROR << "pamUpdatePassword Failed";
1716 }
1717 else if (retval != PAM_SUCCESS)
1718 {
1719 messages::internalError(asyncResp->res);
1720 return;
1721 }
1722 }
1723
Ratan Gupta24c85422019-01-30 19:41:24 +05301724 if (enabled)
1725 {
1726 crow::connections::systemBus->async_method_call(
1727 [asyncResp](const boost::system::error_code ec) {
1728 if (ec)
1729 {
1730 BMCWEB_LOG_ERROR << "D-Bus responses error: "
1731 << ec;
1732 messages::internalError(asyncResp->res);
1733 return;
1734 }
1735 messages::success(asyncResp->res);
1736 return;
1737 },
1738 "xyz.openbmc_project.User.Manager",
1739 dbusObjectPath.c_str(),
1740 "org.freedesktop.DBus.Properties", "Set",
1741 "xyz.openbmc_project.User.Attributes", "UserEnabled",
1742 std::variant<bool>{*enabled});
1743 }
Ed Tanous9712f8a2018-09-21 13:38:49 -07001744
Ratan Gupta24c85422019-01-30 19:41:24 +05301745 if (roleId)
1746 {
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -06001747 std::string priv = getPrivilegeFromRoleId(*roleId);
Ratan Gupta24c85422019-01-30 19:41:24 +05301748 if (priv.empty())
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301749 {
Ratan Gupta24c85422019-01-30 19:41:24 +05301750 messages::propertyValueNotInList(asyncResp->res,
1751 *roleId, "RoleId");
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301752 return;
1753 }
Ratan Gupta24c85422019-01-30 19:41:24 +05301754
1755 crow::connections::systemBus->async_method_call(
1756 [asyncResp](const boost::system::error_code ec) {
1757 if (ec)
1758 {
1759 BMCWEB_LOG_ERROR << "D-Bus responses error: "
1760 << ec;
1761 messages::internalError(asyncResp->res);
1762 return;
1763 }
1764 messages::success(asyncResp->res);
1765 },
1766 "xyz.openbmc_project.User.Manager",
1767 dbusObjectPath.c_str(),
1768 "org.freedesktop.DBus.Properties", "Set",
1769 "xyz.openbmc_project.User.Attributes", "UserPrivilege",
1770 std::variant<std::string>{priv});
1771 }
1772
1773 if (locked)
1774 {
1775 // admin can unlock the account which is locked by
Nagaraju Goruganti54fc5872019-01-30 05:11:00 -06001776 // successive authentication failures but admin should
1777 // not be allowed to lock an account.
Ratan Gupta24c85422019-01-30 19:41:24 +05301778 if (*locked)
1779 {
1780 messages::propertyValueNotInList(asyncResp->res, "true",
1781 "Locked");
1782 return;
1783 }
1784
1785 crow::connections::systemBus->async_method_call(
1786 [asyncResp](const boost::system::error_code ec) {
1787 if (ec)
1788 {
1789 BMCWEB_LOG_ERROR << "D-Bus responses error: "
1790 << ec;
1791 messages::internalError(asyncResp->res);
1792 return;
1793 }
1794 messages::success(asyncResp->res);
1795 return;
1796 },
1797 "xyz.openbmc_project.User.Manager",
1798 dbusObjectPath.c_str(),
1799 "org.freedesktop.DBus.Properties", "Set",
1800 "xyz.openbmc_project.User.Attributes",
1801 "UserLockedForFailedAttempt",
1802 sdbusplus::message::variant<bool>{*locked});
1803 }
1804 });
Ed Tanousa8408792018-09-05 16:08:38 -07001805 }
Ed Tanous06e086d2018-09-19 17:19:52 -07001806
1807 void doDelete(crow::Response& res, const crow::Request& req,
1808 const std::vector<std::string>& params) override
1809 {
1810 auto asyncResp = std::make_shared<AsyncResp>(res);
1811
1812 if (params.size() != 1)
1813 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001814 messages::internalError(asyncResp->res);
Ed Tanous06e086d2018-09-19 17:19:52 -07001815 return;
1816 }
1817
1818 const std::string userPath = "/xyz/openbmc_project/user/" + params[0];
1819
1820 crow::connections::systemBus->async_method_call(
1821 [asyncResp, username{std::move(params[0])}](
1822 const boost::system::error_code ec) {
1823 if (ec)
1824 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001825 messages::resourceNotFound(
1826 asyncResp->res, "#ManagerAccount.v1_0_3.ManagerAccount",
1827 username);
Ed Tanous06e086d2018-09-19 17:19:52 -07001828 return;
1829 }
1830
Jason M. Billsf12894f2018-10-09 12:45:45 -07001831 messages::accountRemoved(asyncResp->res);
Ed Tanous06e086d2018-09-19 17:19:52 -07001832 },
1833 "xyz.openbmc_project.User.Manager", userPath,
1834 "xyz.openbmc_project.Object.Delete", "Delete");
1835 }
AppaRao Puli84e12cb2018-10-11 01:28:15 +05301836};
Lewanczyk, Dawid88d16c92018-02-02 14:51:09 +01001837
Ed Tanous1abe55e2018-09-05 08:30:59 -07001838} // namespace redfish