xref: /openbmc/bmcweb/features/redfish/lib/account_service.hpp (revision 49cc263fdcfc9b279c399c0b03bfd7e9167e06c2)
188d16c9aSLewanczyk, Dawid /*
288d16c9aSLewanczyk, Dawid // Copyright (c) 2018 Intel Corporation
388d16c9aSLewanczyk, Dawid //
488d16c9aSLewanczyk, Dawid // Licensed under the Apache License, Version 2.0 (the "License");
588d16c9aSLewanczyk, Dawid // you may not use this file except in compliance with the License.
688d16c9aSLewanczyk, Dawid // You may obtain a copy of the License at
788d16c9aSLewanczyk, Dawid //
888d16c9aSLewanczyk, Dawid //      http://www.apache.org/licenses/LICENSE-2.0
988d16c9aSLewanczyk, Dawid //
1088d16c9aSLewanczyk, Dawid // Unless required by applicable law or agreed to in writing, software
1188d16c9aSLewanczyk, Dawid // distributed under the License is distributed on an "AS IS" BASIS,
1288d16c9aSLewanczyk, Dawid // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1388d16c9aSLewanczyk, Dawid // See the License for the specific language governing permissions and
1488d16c9aSLewanczyk, Dawid // limitations under the License.
1588d16c9aSLewanczyk, Dawid */
1688d16c9aSLewanczyk, Dawid #pragma once
1788d16c9aSLewanczyk, Dawid 
183ccb3adbSEd Tanous #include "app.hpp"
193ccb3adbSEd Tanous #include "dbus_utility.hpp"
203ccb3adbSEd Tanous #include "error_messages.hpp"
210ec8b83dSEd Tanous #include "generated/enums/account_service.hpp"
223ccb3adbSEd Tanous #include "openbmc_dbus_rest.hpp"
233ccb3adbSEd Tanous #include "persistent_data.hpp"
243ccb3adbSEd Tanous #include "query.hpp"
250ec8b83dSEd Tanous #include "registries/privilege_registry.hpp"
263ccb3adbSEd Tanous #include "utils/dbus_utils.hpp"
273ccb3adbSEd Tanous #include "utils/json_utils.hpp"
280ec8b83dSEd Tanous 
291e1e598dSJonathan Doman #include <sdbusplus/asio/property.hpp>
30d1bde9e5SKrzysztof Grobelny #include <sdbusplus/unpack_properties.hpp>
311214b7e7SGunnar Mills 
322b73119cSGeorge Liu #include <array>
33c7229815SAbhishek Patel #include <optional>
343544d2a7SEd Tanous #include <ranges>
35c7229815SAbhishek Patel #include <string>
362b73119cSGeorge Liu #include <string_view>
37c7229815SAbhishek Patel #include <vector>
38c7229815SAbhishek Patel 
391abe55efSEd Tanous namespace redfish
401abe55efSEd Tanous {
4188d16c9aSLewanczyk, Dawid 
4223a21a1cSEd Tanous constexpr const char* ldapConfigObjectName =
436973a582SRatan Gupta     "/xyz/openbmc_project/user/ldap/openldap";
442c70f800SEd Tanous constexpr const char* adConfigObject =
45ab828d7cSRatan Gupta     "/xyz/openbmc_project/user/ldap/active_directory";
46ab828d7cSRatan Gupta 
47b477fd44SP Dheeraj Srujan Kumar constexpr const char* rootUserDbusPath = "/xyz/openbmc_project/user/";
486973a582SRatan Gupta constexpr const char* ldapRootObject = "/xyz/openbmc_project/user/ldap";
496973a582SRatan Gupta constexpr const char* ldapDbusService = "xyz.openbmc_project.Ldap.Config";
506973a582SRatan Gupta constexpr const char* ldapConfigInterface =
516973a582SRatan Gupta     "xyz.openbmc_project.User.Ldap.Config";
526973a582SRatan Gupta constexpr const char* ldapCreateInterface =
536973a582SRatan Gupta     "xyz.openbmc_project.User.Ldap.Create";
546973a582SRatan Gupta constexpr const char* ldapEnableInterface = "xyz.openbmc_project.Object.Enable";
5506785244SRatan Gupta constexpr const char* ldapPrivMapperInterface =
5606785244SRatan Gupta     "xyz.openbmc_project.User.PrivilegeMapper";
576973a582SRatan Gupta 
5854fc587aSNagaraju Goruganti struct LDAPRoleMapData
5954fc587aSNagaraju Goruganti {
6054fc587aSNagaraju Goruganti     std::string groupName;
6154fc587aSNagaraju Goruganti     std::string privilege;
6254fc587aSNagaraju Goruganti };
6354fc587aSNagaraju Goruganti 
646973a582SRatan Gupta struct LDAPConfigData
656973a582SRatan Gupta {
6647f2934cSEd Tanous     std::string uri;
6747f2934cSEd Tanous     std::string bindDN;
6847f2934cSEd Tanous     std::string baseDN;
6947f2934cSEd Tanous     std::string searchScope;
7047f2934cSEd Tanous     std::string serverType;
716973a582SRatan Gupta     bool serviceEnabled = false;
7247f2934cSEd Tanous     std::string userNameAttribute;
7347f2934cSEd Tanous     std::string groupAttribute;
7454fc587aSNagaraju Goruganti     std::vector<std::pair<std::string, LDAPRoleMapData>> groupRoleList;
756973a582SRatan Gupta };
766973a582SRatan Gupta 
7754fc587aSNagaraju Goruganti inline std::string getRoleIdFromPrivilege(std::string_view role)
7884e12cb7SAppaRao Puli {
7984e12cb7SAppaRao Puli     if (role == "priv-admin")
8084e12cb7SAppaRao Puli     {
8184e12cb7SAppaRao Puli         return "Administrator";
8284e12cb7SAppaRao Puli     }
833174e4dfSEd Tanous     if (role == "priv-user")
8484e12cb7SAppaRao Puli     {
85c80fee55SAppaRao Puli         return "ReadOnly";
8684e12cb7SAppaRao Puli     }
873174e4dfSEd Tanous     if (role == "priv-operator")
8884e12cb7SAppaRao Puli     {
8984e12cb7SAppaRao Puli         return "Operator";
9084e12cb7SAppaRao Puli     }
9184e12cb7SAppaRao Puli     return "";
9284e12cb7SAppaRao Puli }
9354fc587aSNagaraju Goruganti inline std::string getPrivilegeFromRoleId(std::string_view role)
9484e12cb7SAppaRao Puli {
9584e12cb7SAppaRao Puli     if (role == "Administrator")
9684e12cb7SAppaRao Puli     {
9784e12cb7SAppaRao Puli         return "priv-admin";
9884e12cb7SAppaRao Puli     }
993174e4dfSEd Tanous     if (role == "ReadOnly")
10084e12cb7SAppaRao Puli     {
10184e12cb7SAppaRao Puli         return "priv-user";
10284e12cb7SAppaRao Puli     }
1033174e4dfSEd Tanous     if (role == "Operator")
10484e12cb7SAppaRao Puli     {
10584e12cb7SAppaRao Puli         return "priv-operator";
10684e12cb7SAppaRao Puli     }
10784e12cb7SAppaRao Puli     return "";
10884e12cb7SAppaRao Puli }
109b9b2e0b2SEd Tanous 
110c7229815SAbhishek Patel /**
111c7229815SAbhishek Patel  * @brief Maps user group names retrieved from D-Bus object to
112c7229815SAbhishek Patel  * Account Types.
113c7229815SAbhishek Patel  *
114c7229815SAbhishek Patel  * @param[in] userGroups List of User groups
115c7229815SAbhishek Patel  * @param[out] res AccountTypes populated
116c7229815SAbhishek Patel  *
117c7229815SAbhishek Patel  * @return true in case of success, false if UserGroups contains
118c7229815SAbhishek Patel  * invalid group name(s).
119c7229815SAbhishek Patel  */
120c7229815SAbhishek Patel inline bool translateUserGroup(const std::vector<std::string>& userGroups,
121c7229815SAbhishek Patel                                crow::Response& res)
122c7229815SAbhishek Patel {
123c7229815SAbhishek Patel     std::vector<std::string> accountTypes;
124c7229815SAbhishek Patel     for (const auto& userGroup : userGroups)
125c7229815SAbhishek Patel     {
126c7229815SAbhishek Patel         if (userGroup == "redfish")
127c7229815SAbhishek Patel         {
128c7229815SAbhishek Patel             accountTypes.emplace_back("Redfish");
129c7229815SAbhishek Patel             accountTypes.emplace_back("WebUI");
130c7229815SAbhishek Patel         }
131c7229815SAbhishek Patel         else if (userGroup == "ipmi")
132c7229815SAbhishek Patel         {
133c7229815SAbhishek Patel             accountTypes.emplace_back("IPMI");
134c7229815SAbhishek Patel         }
135c7229815SAbhishek Patel         else if (userGroup == "ssh")
136c7229815SAbhishek Patel         {
137c7229815SAbhishek Patel             accountTypes.emplace_back("ManagerConsole");
138c7229815SAbhishek Patel         }
1393e72c202SNinad Palsule         else if (userGroup == "hostconsole")
1403e72c202SNinad Palsule         {
1413e72c202SNinad Palsule             // The hostconsole group controls who can access the host console
1423e72c202SNinad Palsule             // port via ssh and websocket.
1433e72c202SNinad Palsule             accountTypes.emplace_back("HostConsole");
1443e72c202SNinad Palsule         }
145c7229815SAbhishek Patel         else if (userGroup == "web")
146c7229815SAbhishek Patel         {
147c7229815SAbhishek Patel             // 'web' is one of the valid groups in the UserGroups property of
148c7229815SAbhishek Patel             // the user account in the D-Bus object. This group is currently not
149c7229815SAbhishek Patel             // doing anything, and is considered to be equivalent to 'redfish'.
150c7229815SAbhishek Patel             // 'redfish' user group is mapped to 'Redfish'and 'WebUI'
151c7229815SAbhishek Patel             // AccountTypes, so do nothing here...
152c7229815SAbhishek Patel         }
153c7229815SAbhishek Patel         else
154c7229815SAbhishek Patel         {
1558ece0e45SEd Tanous             // Invalid user group name. Caller throws an exception.
156c7229815SAbhishek Patel             return false;
157c7229815SAbhishek Patel         }
158c7229815SAbhishek Patel     }
159c7229815SAbhishek Patel 
160c7229815SAbhishek Patel     res.jsonValue["AccountTypes"] = std::move(accountTypes);
161c7229815SAbhishek Patel     return true;
162c7229815SAbhishek Patel }
163c7229815SAbhishek Patel 
16458345856SAbhishek Patel /**
16558345856SAbhishek Patel  * @brief Builds User Groups from the Account Types
16658345856SAbhishek Patel  *
16758345856SAbhishek Patel  * @param[in] asyncResp Async Response
16858345856SAbhishek Patel  * @param[in] accountTypes List of Account Types
16958345856SAbhishek Patel  * @param[out] userGroups List of User Groups mapped from Account Types
17058345856SAbhishek Patel  *
17158345856SAbhishek Patel  * @return true if Account Types mapped to User Groups, false otherwise.
17258345856SAbhishek Patel  */
17358345856SAbhishek Patel inline bool
17458345856SAbhishek Patel     getUserGroupFromAccountType(crow::Response& res,
17558345856SAbhishek Patel                                 const std::vector<std::string>& accountTypes,
17658345856SAbhishek Patel                                 std::vector<std::string>& userGroups)
17758345856SAbhishek Patel {
17858345856SAbhishek Patel     // Need both Redfish and WebUI Account Types to map to 'redfish' User Group
17958345856SAbhishek Patel     bool redfishType = false;
18058345856SAbhishek Patel     bool webUIType = false;
18158345856SAbhishek Patel 
18258345856SAbhishek Patel     for (const auto& accountType : accountTypes)
18358345856SAbhishek Patel     {
18458345856SAbhishek Patel         if (accountType == "Redfish")
18558345856SAbhishek Patel         {
18658345856SAbhishek Patel             redfishType = true;
18758345856SAbhishek Patel         }
18858345856SAbhishek Patel         else if (accountType == "WebUI")
18958345856SAbhishek Patel         {
19058345856SAbhishek Patel             webUIType = true;
19158345856SAbhishek Patel         }
19258345856SAbhishek Patel         else if (accountType == "IPMI")
19358345856SAbhishek Patel         {
19458345856SAbhishek Patel             userGroups.emplace_back("ipmi");
19558345856SAbhishek Patel         }
19658345856SAbhishek Patel         else if (accountType == "HostConsole")
19758345856SAbhishek Patel         {
19858345856SAbhishek Patel             userGroups.emplace_back("hostconsole");
19958345856SAbhishek Patel         }
20058345856SAbhishek Patel         else if (accountType == "ManagerConsole")
20158345856SAbhishek Patel         {
20258345856SAbhishek Patel             userGroups.emplace_back("ssh");
20358345856SAbhishek Patel         }
20458345856SAbhishek Patel         else
20558345856SAbhishek Patel         {
20658345856SAbhishek Patel             // Invalid Account Type
20758345856SAbhishek Patel             messages::propertyValueNotInList(res, "AccountTypes", accountType);
20858345856SAbhishek Patel             return false;
20958345856SAbhishek Patel         }
21058345856SAbhishek Patel     }
21158345856SAbhishek Patel 
21258345856SAbhishek Patel     // Both  Redfish and WebUI Account Types are needed to PATCH
21358345856SAbhishek Patel     if (redfishType ^ webUIType)
21458345856SAbhishek Patel     {
21562598e31SEd Tanous         BMCWEB_LOG_ERROR(
21662598e31SEd Tanous             "Missing Redfish or WebUI Account Type to set redfish User Group");
21758345856SAbhishek Patel         messages::strictAccountTypes(res, "AccountTypes");
21858345856SAbhishek Patel         return false;
21958345856SAbhishek Patel     }
22058345856SAbhishek Patel 
22158345856SAbhishek Patel     if (redfishType && webUIType)
22258345856SAbhishek Patel     {
22358345856SAbhishek Patel         userGroups.emplace_back("redfish");
22458345856SAbhishek Patel     }
22558345856SAbhishek Patel 
22658345856SAbhishek Patel     return true;
22758345856SAbhishek Patel }
22858345856SAbhishek Patel 
22958345856SAbhishek Patel /**
23058345856SAbhishek Patel  * @brief Sets UserGroups property of the user based on the Account Types
23158345856SAbhishek Patel  *
23258345856SAbhishek Patel  * @param[in] accountTypes List of User Account Types
23358345856SAbhishek Patel  * @param[in] asyncResp Async Response
23458345856SAbhishek Patel  * @param[in] dbusObjectPath D-Bus Object Path
23558345856SAbhishek Patel  * @param[in] userSelf true if User is updating OWN Account Types
23658345856SAbhishek Patel  */
23758345856SAbhishek Patel inline void
23858345856SAbhishek Patel     patchAccountTypes(const std::vector<std::string>& accountTypes,
23958345856SAbhishek Patel                       const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
24058345856SAbhishek Patel                       const std::string& dbusObjectPath, bool userSelf)
24158345856SAbhishek Patel {
24258345856SAbhishek Patel     // Check if User is disabling own Redfish Account Type
24358345856SAbhishek Patel     if (userSelf &&
24458345856SAbhishek Patel         (accountTypes.cend() ==
24558345856SAbhishek Patel          std::find(accountTypes.cbegin(), accountTypes.cend(), "Redfish")))
24658345856SAbhishek Patel     {
24762598e31SEd Tanous         BMCWEB_LOG_ERROR(
24862598e31SEd Tanous             "User disabling OWN Redfish Account Type is not allowed");
24958345856SAbhishek Patel         messages::strictAccountTypes(asyncResp->res, "AccountTypes");
25058345856SAbhishek Patel         return;
25158345856SAbhishek Patel     }
25258345856SAbhishek Patel 
25358345856SAbhishek Patel     std::vector<std::string> updatedUserGroups;
25458345856SAbhishek Patel     if (!getUserGroupFromAccountType(asyncResp->res, accountTypes,
25558345856SAbhishek Patel                                      updatedUserGroups))
25658345856SAbhishek Patel     {
25758345856SAbhishek Patel         // Problem in mapping Account Types to User Groups, Error already
25858345856SAbhishek Patel         // logged.
25958345856SAbhishek Patel         return;
26058345856SAbhishek Patel     }
26158345856SAbhishek Patel 
2629ae226faSGeorge Liu     sdbusplus::asio::setProperty(
2639ae226faSGeorge Liu         *crow::connections::systemBus, "xyz.openbmc_project.User.Manager",
2649ae226faSGeorge Liu         dbusObjectPath, "xyz.openbmc_project.User.Attributes", "UserGroups",
2659ae226faSGeorge Liu         updatedUserGroups, [asyncResp](const boost::system::error_code& ec) {
26658345856SAbhishek Patel         if (ec)
26758345856SAbhishek Patel         {
26862598e31SEd Tanous             BMCWEB_LOG_ERROR("D-Bus responses error: {}", ec);
26958345856SAbhishek Patel             messages::internalError(asyncResp->res);
27058345856SAbhishek Patel             return;
27158345856SAbhishek Patel         }
27258345856SAbhishek Patel         messages::success(asyncResp->res);
2739ae226faSGeorge Liu     });
27458345856SAbhishek Patel }
27558345856SAbhishek Patel 
2768d1b46d7Szhanghch05 inline void userErrorMessageHandler(
2778d1b46d7Szhanghch05     const sd_bus_error* e, const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2788d1b46d7Szhanghch05     const std::string& newUser, const std::string& username)
27966b5ca76Sjayaprakash Mutyala {
28066b5ca76Sjayaprakash Mutyala     if (e == nullptr)
28166b5ca76Sjayaprakash Mutyala     {
28266b5ca76Sjayaprakash Mutyala         messages::internalError(asyncResp->res);
28366b5ca76Sjayaprakash Mutyala         return;
28466b5ca76Sjayaprakash Mutyala     }
28566b5ca76Sjayaprakash Mutyala 
286055806b3SManojkiran Eda     const char* errorMessage = e->name;
28766b5ca76Sjayaprakash Mutyala     if (strcmp(errorMessage,
28866b5ca76Sjayaprakash Mutyala                "xyz.openbmc_project.User.Common.Error.UserNameExists") == 0)
28966b5ca76Sjayaprakash Mutyala     {
290d8a5d5d8SJiaqing Zhao         messages::resourceAlreadyExists(asyncResp->res, "ManagerAccount",
29166b5ca76Sjayaprakash Mutyala                                         "UserName", newUser);
29266b5ca76Sjayaprakash Mutyala     }
29366b5ca76Sjayaprakash Mutyala     else if (strcmp(errorMessage, "xyz.openbmc_project.User.Common.Error."
29466b5ca76Sjayaprakash Mutyala                                   "UserNameDoesNotExist") == 0)
29566b5ca76Sjayaprakash Mutyala     {
296d8a5d5d8SJiaqing Zhao         messages::resourceNotFound(asyncResp->res, "ManagerAccount", username);
29766b5ca76Sjayaprakash Mutyala     }
298d4d25793SEd Tanous     else if ((strcmp(errorMessage,
299d4d25793SEd Tanous                      "xyz.openbmc_project.Common.Error.InvalidArgument") ==
300d4d25793SEd Tanous               0) ||
3010fda0f12SGeorge Liu              (strcmp(
3020fda0f12SGeorge Liu                   errorMessage,
3030fda0f12SGeorge Liu                   "xyz.openbmc_project.User.Common.Error.UserNameGroupFail") ==
3040fda0f12SGeorge Liu               0))
30566b5ca76Sjayaprakash Mutyala     {
30666b5ca76Sjayaprakash Mutyala         messages::propertyValueFormatError(asyncResp->res, newUser, "UserName");
30766b5ca76Sjayaprakash Mutyala     }
30866b5ca76Sjayaprakash Mutyala     else if (strcmp(errorMessage,
30966b5ca76Sjayaprakash Mutyala                     "xyz.openbmc_project.User.Common.Error.NoResource") == 0)
31066b5ca76Sjayaprakash Mutyala     {
31166b5ca76Sjayaprakash Mutyala         messages::createLimitReachedForResource(asyncResp->res);
31266b5ca76Sjayaprakash Mutyala     }
31366b5ca76Sjayaprakash Mutyala     else
31466b5ca76Sjayaprakash Mutyala     {
315b8ad583fSGunnar Mills         BMCWEB_LOG_ERROR("DBUS response error {}", errorMessage);
31666b5ca76Sjayaprakash Mutyala         messages::internalError(asyncResp->res);
31766b5ca76Sjayaprakash Mutyala     }
31866b5ca76Sjayaprakash Mutyala }
31966b5ca76Sjayaprakash Mutyala 
32081ce609eSEd Tanous inline void parseLDAPConfigData(nlohmann::json& jsonResponse,
321ab828d7cSRatan Gupta                                 const LDAPConfigData& confData,
322ab828d7cSRatan Gupta                                 const std::string& ldapType)
3236973a582SRatan Gupta {
324*49cc263fSEd Tanous     nlohmann::json::object_t ldap;
3251476687dSEd Tanous     ldap["ServiceEnabled"] = confData.serviceEnabled;
326*49cc263fSEd Tanous     nlohmann::json::array_t serviceAddresses;
327*49cc263fSEd Tanous     serviceAddresses.emplace_back(confData.uri);
328*49cc263fSEd Tanous     ldap["ServiceAddresses"] = std::move(serviceAddresses);
329*49cc263fSEd Tanous 
330*49cc263fSEd Tanous     nlohmann::json::object_t authentication;
331*49cc263fSEd Tanous     authentication["AuthenticationType"] =
3320ec8b83dSEd Tanous         account_service::AuthenticationTypes::UsernameAndPassword;
333*49cc263fSEd Tanous     authentication["Username"] = confData.bindDN;
334*49cc263fSEd Tanous     authentication["Password"] = nullptr;
335*49cc263fSEd Tanous     ldap["Authentication"] = std::move(authentication);
3361476687dSEd Tanous 
337*49cc263fSEd Tanous     nlohmann::json::object_t ldapService;
338*49cc263fSEd Tanous     nlohmann::json::object_t searchSettings;
339*49cc263fSEd Tanous     nlohmann::json::array_t baseDistinguishedNames;
340*49cc263fSEd Tanous     baseDistinguishedNames.emplace_back(confData.baseDN);
3411476687dSEd Tanous 
342*49cc263fSEd Tanous     searchSettings["BaseDistinguishedNames"] =
343*49cc263fSEd Tanous         std::move(baseDistinguishedNames);
344*49cc263fSEd Tanous     searchSettings["UsernameAttribute"] = confData.userNameAttribute;
345*49cc263fSEd Tanous     searchSettings["GroupsAttribute"] = confData.groupAttribute;
346*49cc263fSEd Tanous     ldapService["SearchSettings"] = std::move(searchSettings);
347*49cc263fSEd Tanous     ldap["LDAPService"] = std::move(ldapService);
348*49cc263fSEd Tanous 
349*49cc263fSEd Tanous     nlohmann::json::array_t roleMapArray;
3509eb808c1SEd Tanous     for (const auto& obj : confData.groupRoleList)
35154fc587aSNagaraju Goruganti     {
35262598e31SEd Tanous         BMCWEB_LOG_DEBUG("Pushing the data groupName={}", obj.second.groupName);
353613dabeaSEd Tanous 
354613dabeaSEd Tanous         nlohmann::json::object_t remoteGroup;
355613dabeaSEd Tanous         remoteGroup["RemoteGroup"] = obj.second.groupName;
356329f0348SJorge Cisneros         remoteGroup["LocalRole"] = getRoleIdFromPrivilege(obj.second.privilege);
357329f0348SJorge Cisneros         roleMapArray.emplace_back(std::move(remoteGroup));
35854fc587aSNagaraju Goruganti     }
359*49cc263fSEd Tanous 
360*49cc263fSEd Tanous     ldap["RemoteRoleMapping"] = std::move(roleMapArray);
361*49cc263fSEd Tanous 
362*49cc263fSEd Tanous     jsonResponse[ldapType].update(ldap);
3636973a582SRatan Gupta }
3646973a582SRatan Gupta 
3656973a582SRatan Gupta /**
36606785244SRatan Gupta  *  @brief validates given JSON input and then calls appropriate method to
36706785244SRatan Gupta  * create, to delete or to set Rolemapping object based on the given input.
36806785244SRatan Gupta  *
36906785244SRatan Gupta  */
37023a21a1cSEd Tanous inline void handleRoleMapPatch(
3718d1b46d7Szhanghch05     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
37206785244SRatan Gupta     const std::vector<std::pair<std::string, LDAPRoleMapData>>& roleMapObjData,
373f23b7296SEd Tanous     const std::string& serverType, const std::vector<nlohmann::json>& input)
37406785244SRatan Gupta {
37506785244SRatan Gupta     for (size_t index = 0; index < input.size(); index++)
37606785244SRatan Gupta     {
377f23b7296SEd Tanous         const nlohmann::json& thisJson = input[index];
37806785244SRatan Gupta 
37906785244SRatan Gupta         if (thisJson.is_null())
38006785244SRatan Gupta         {
38106785244SRatan Gupta             // delete the existing object
38206785244SRatan Gupta             if (index < roleMapObjData.size())
38306785244SRatan Gupta             {
38406785244SRatan Gupta                 crow::connections::systemBus->async_method_call(
38506785244SRatan Gupta                     [asyncResp, roleMapObjData, serverType,
3865e7e2dc5SEd Tanous                      index](const boost::system::error_code& ec) {
38706785244SRatan Gupta                     if (ec)
38806785244SRatan Gupta                     {
38962598e31SEd Tanous                         BMCWEB_LOG_ERROR("DBUS response error: {}", ec);
39006785244SRatan Gupta                         messages::internalError(asyncResp->res);
39106785244SRatan Gupta                         return;
39206785244SRatan Gupta                     }
39389492a15SPatrick Williams                     asyncResp->res.jsonValue[serverType]["RemoteRoleMapping"]
39489492a15SPatrick Williams                                             [index] = nullptr;
39506785244SRatan Gupta                 },
39606785244SRatan Gupta                     ldapDbusService, roleMapObjData[index].first,
39706785244SRatan Gupta                     "xyz.openbmc_project.Object.Delete", "Delete");
39806785244SRatan Gupta             }
39906785244SRatan Gupta             else
40006785244SRatan Gupta             {
40162598e31SEd Tanous                 BMCWEB_LOG_ERROR("Can't delete the object");
4022e8c4bdaSEd Tanous                 messages::propertyValueTypeError(asyncResp->res, thisJson,
4032e8c4bdaSEd Tanous                                                  "RemoteRoleMapping/" +
4042e8c4bdaSEd Tanous                                                      std::to_string(index));
40506785244SRatan Gupta                 return;
40606785244SRatan Gupta             }
40706785244SRatan Gupta         }
40806785244SRatan Gupta         else if (thisJson.empty())
40906785244SRatan Gupta         {
41006785244SRatan Gupta             // Don't do anything for the empty objects,parse next json
41106785244SRatan Gupta             // eg {"RemoteRoleMapping",[{}]}
41206785244SRatan Gupta         }
41306785244SRatan Gupta         else
41406785244SRatan Gupta         {
41506785244SRatan Gupta             // update/create the object
41606785244SRatan Gupta             std::optional<std::string> remoteGroup;
41706785244SRatan Gupta             std::optional<std::string> localRole;
41806785244SRatan Gupta 
419f23b7296SEd Tanous             // This is a copy, but it's required in this case because of how
420f23b7296SEd Tanous             // readJson is structured
421f23b7296SEd Tanous             nlohmann::json thisJsonCopy = thisJson;
422f23b7296SEd Tanous             if (!json_util::readJson(thisJsonCopy, asyncResp->res,
423f23b7296SEd Tanous                                      "RemoteGroup", remoteGroup, "LocalRole",
424f23b7296SEd Tanous                                      localRole))
42506785244SRatan Gupta             {
42606785244SRatan Gupta                 continue;
42706785244SRatan Gupta             }
42806785244SRatan Gupta 
42906785244SRatan Gupta             // Update existing RoleMapping Object
43006785244SRatan Gupta             if (index < roleMapObjData.size())
43106785244SRatan Gupta             {
43262598e31SEd Tanous                 BMCWEB_LOG_DEBUG("Update Role Map Object");
43306785244SRatan Gupta                 // If "RemoteGroup" info is provided
43406785244SRatan Gupta                 if (remoteGroup)
43506785244SRatan Gupta                 {
4369ae226faSGeorge Liu                     sdbusplus::asio::setProperty(
4379ae226faSGeorge Liu                         *crow::connections::systemBus, ldapDbusService,
4389ae226faSGeorge Liu                         roleMapObjData[index].first,
4399ae226faSGeorge Liu                         "xyz.openbmc_project.User.PrivilegeMapperEntry",
4409ae226faSGeorge Liu                         "GroupName", *remoteGroup,
44106785244SRatan Gupta                         [asyncResp, roleMapObjData, serverType, index,
44225e055a3SRavi Teja                          remoteGroup](const boost::system::error_code& ec,
4437a543894SPatrick Williams                                       const sdbusplus::message_t& msg) {
44406785244SRatan Gupta                         if (ec)
44506785244SRatan Gupta                         {
44625e055a3SRavi Teja                             const sd_bus_error* dbusError = msg.get_error();
44725e055a3SRavi Teja                             if ((dbusError != nullptr) &&
44825e055a3SRavi Teja                                 (dbusError->name ==
44925e055a3SRavi Teja                                  std::string_view(
45025e055a3SRavi Teja                                      "xyz.openbmc_project.Common.Error.InvalidArgument")))
45125e055a3SRavi Teja                             {
45262598e31SEd Tanous                                 BMCWEB_LOG_WARNING("DBUS response error: {}",
45362598e31SEd Tanous                                                    ec);
45425e055a3SRavi Teja                                 messages::propertyValueIncorrect(asyncResp->res,
45525e055a3SRavi Teja                                                                  "RemoteGroup",
45625e055a3SRavi Teja                                                                  *remoteGroup);
45725e055a3SRavi Teja                                 return;
45825e055a3SRavi Teja                             }
45906785244SRatan Gupta                             messages::internalError(asyncResp->res);
46006785244SRatan Gupta                             return;
46106785244SRatan Gupta                         }
46206785244SRatan Gupta                         asyncResp->res
463002d39b4SEd Tanous                             .jsonValue[serverType]["RemoteRoleMapping"][index]
464002d39b4SEd Tanous                                       ["RemoteGroup"] = *remoteGroup;
4659ae226faSGeorge Liu                     });
46606785244SRatan Gupta                 }
46706785244SRatan Gupta 
46806785244SRatan Gupta                 // If "LocalRole" info is provided
46906785244SRatan Gupta                 if (localRole)
47006785244SRatan Gupta                 {
4719ae226faSGeorge Liu                     sdbusplus::asio::setProperty(
4729ae226faSGeorge Liu                         *crow::connections::systemBus, ldapDbusService,
4739ae226faSGeorge Liu                         roleMapObjData[index].first,
4749ae226faSGeorge Liu                         "xyz.openbmc_project.User.PrivilegeMapperEntry",
4759ae226faSGeorge Liu                         "Privilege", *localRole,
47606785244SRatan Gupta                         [asyncResp, roleMapObjData, serverType, index,
47725e055a3SRavi Teja                          localRole](const boost::system::error_code& ec,
4787a543894SPatrick Williams                                     const sdbusplus::message_t& msg) {
47906785244SRatan Gupta                         if (ec)
48006785244SRatan Gupta                         {
48125e055a3SRavi Teja                             const sd_bus_error* dbusError = msg.get_error();
48225e055a3SRavi Teja                             if ((dbusError != nullptr) &&
48325e055a3SRavi Teja                                 (dbusError->name ==
48425e055a3SRavi Teja                                  std::string_view(
48525e055a3SRavi Teja                                      "xyz.openbmc_project.Common.Error.InvalidArgument")))
48625e055a3SRavi Teja                             {
48762598e31SEd Tanous                                 BMCWEB_LOG_WARNING("DBUS response error: {}",
48862598e31SEd Tanous                                                    ec);
48925e055a3SRavi Teja                                 messages::propertyValueIncorrect(
49025e055a3SRavi Teja                                     asyncResp->res, "LocalRole", *localRole);
49125e055a3SRavi Teja                                 return;
49225e055a3SRavi Teja                             }
49306785244SRatan Gupta                             messages::internalError(asyncResp->res);
49406785244SRatan Gupta                             return;
49506785244SRatan Gupta                         }
49606785244SRatan Gupta                         asyncResp->res
497002d39b4SEd Tanous                             .jsonValue[serverType]["RemoteRoleMapping"][index]
498002d39b4SEd Tanous                                       ["LocalRole"] = *localRole;
4999ae226faSGeorge Liu                     });
50006785244SRatan Gupta                 }
50106785244SRatan Gupta             }
50206785244SRatan Gupta             // Create a new RoleMapping Object.
50306785244SRatan Gupta             else
50406785244SRatan Gupta             {
50562598e31SEd Tanous                 BMCWEB_LOG_DEBUG(
50662598e31SEd Tanous                     "setRoleMappingProperties: Creating new Object");
50789492a15SPatrick Williams                 std::string pathString = "RemoteRoleMapping/" +
50889492a15SPatrick Williams                                          std::to_string(index);
50906785244SRatan Gupta 
51006785244SRatan Gupta                 if (!localRole)
51106785244SRatan Gupta                 {
51206785244SRatan Gupta                     messages::propertyMissing(asyncResp->res,
51306785244SRatan Gupta                                               pathString + "/LocalRole");
51406785244SRatan Gupta                     continue;
51506785244SRatan Gupta                 }
51606785244SRatan Gupta                 if (!remoteGroup)
51706785244SRatan Gupta                 {
51806785244SRatan Gupta                     messages::propertyMissing(asyncResp->res,
51906785244SRatan Gupta                                               pathString + "/RemoteGroup");
52006785244SRatan Gupta                     continue;
52106785244SRatan Gupta                 }
52206785244SRatan Gupta 
52306785244SRatan Gupta                 std::string dbusObjectPath;
52406785244SRatan Gupta                 if (serverType == "ActiveDirectory")
52506785244SRatan Gupta                 {
5262c70f800SEd Tanous                     dbusObjectPath = adConfigObject;
52706785244SRatan Gupta                 }
52806785244SRatan Gupta                 else if (serverType == "LDAP")
52906785244SRatan Gupta                 {
53023a21a1cSEd Tanous                     dbusObjectPath = ldapConfigObjectName;
53106785244SRatan Gupta                 }
53206785244SRatan Gupta 
53362598e31SEd Tanous                 BMCWEB_LOG_DEBUG("Remote Group={},LocalRole={}", *remoteGroup,
53462598e31SEd Tanous                                  *localRole);
53506785244SRatan Gupta 
53606785244SRatan Gupta                 crow::connections::systemBus->async_method_call(
537271584abSEd Tanous                     [asyncResp, serverType, localRole,
5385e7e2dc5SEd Tanous                      remoteGroup](const boost::system::error_code& ec) {
53906785244SRatan Gupta                     if (ec)
54006785244SRatan Gupta                     {
54162598e31SEd Tanous                         BMCWEB_LOG_ERROR("DBUS response error: {}", ec);
54206785244SRatan Gupta                         messages::internalError(asyncResp->res);
54306785244SRatan Gupta                         return;
54406785244SRatan Gupta                     }
54506785244SRatan Gupta                     nlohmann::json& remoteRoleJson =
54606785244SRatan Gupta                         asyncResp->res
54706785244SRatan Gupta                             .jsonValue[serverType]["RemoteRoleMapping"];
5481476687dSEd Tanous                     nlohmann::json::object_t roleMapEntry;
5491476687dSEd Tanous                     roleMapEntry["LocalRole"] = *localRole;
5501476687dSEd Tanous                     roleMapEntry["RemoteGroup"] = *remoteGroup;
551b2ba3072SPatrick Williams                     remoteRoleJson.emplace_back(std::move(roleMapEntry));
55206785244SRatan Gupta                 },
55306785244SRatan Gupta                     ldapDbusService, dbusObjectPath, ldapPrivMapperInterface,
5543174e4dfSEd Tanous                     "Create", *remoteGroup,
55506785244SRatan Gupta                     getPrivilegeFromRoleId(std::move(*localRole)));
55606785244SRatan Gupta             }
55706785244SRatan Gupta         }
55806785244SRatan Gupta     }
55906785244SRatan Gupta }
56006785244SRatan Gupta 
56106785244SRatan Gupta /**
5626973a582SRatan Gupta  * Function that retrieves all properties for LDAP config object
5636973a582SRatan Gupta  * into JSON
5646973a582SRatan Gupta  */
5656973a582SRatan Gupta template <typename CallbackFunc>
5666973a582SRatan Gupta inline void getLDAPConfigData(const std::string& ldapType,
5676973a582SRatan Gupta                               CallbackFunc&& callback)
5686973a582SRatan Gupta {
5692b73119cSGeorge Liu     constexpr std::array<std::string_view, 2> interfaces = {
5702b73119cSGeorge Liu         ldapEnableInterface, ldapConfigInterface};
57154fc587aSNagaraju Goruganti 
5722b73119cSGeorge Liu     dbus::utility::getDbusObject(
5732b73119cSGeorge Liu         ldapConfigObjectName, interfaces,
5742b73119cSGeorge Liu         [callback, ldapType](const boost::system::error_code& ec,
575b9d36b47SEd Tanous                              const dbus::utility::MapperGetObject& resp) {
57654fc587aSNagaraju Goruganti         if (ec || resp.empty())
57754fc587aSNagaraju Goruganti         {
578bf2ddedeSCarson Labrado             BMCWEB_LOG_WARNING(
57962598e31SEd Tanous                 "DBUS response error during getting of service name: {}", ec);
58023a21a1cSEd Tanous             LDAPConfigData empty{};
58123a21a1cSEd Tanous             callback(false, empty, ldapType);
58254fc587aSNagaraju Goruganti             return;
58354fc587aSNagaraju Goruganti         }
58454fc587aSNagaraju Goruganti         std::string service = resp.begin()->first;
5855eb468daSGeorge Liu         sdbusplus::message::object_path path(ldapRootObject);
5865eb468daSGeorge Liu         dbus::utility::getManagedObjects(
5875eb468daSGeorge Liu             service, path,
588002d39b4SEd Tanous             [callback,
5898b24275dSEd Tanous              ldapType](const boost::system::error_code& ec2,
590711ac7a9SEd Tanous                        const dbus::utility::ManagedObjectType& ldapObjects) {
5916973a582SRatan Gupta             LDAPConfigData confData{};
5928b24275dSEd Tanous             if (ec2)
5936973a582SRatan Gupta             {
594ab828d7cSRatan Gupta                 callback(false, confData, ldapType);
595bf2ddedeSCarson Labrado                 BMCWEB_LOG_WARNING("D-Bus responses error: {}", ec2);
5966973a582SRatan Gupta                 return;
5976973a582SRatan Gupta             }
598ab828d7cSRatan Gupta 
599ab828d7cSRatan Gupta             std::string ldapDbusType;
60054fc587aSNagaraju Goruganti             std::string searchString;
60154fc587aSNagaraju Goruganti 
602ab828d7cSRatan Gupta             if (ldapType == "LDAP")
603ab828d7cSRatan Gupta             {
6040fda0f12SGeorge Liu                 ldapDbusType =
6050fda0f12SGeorge Liu                     "xyz.openbmc_project.User.Ldap.Config.Type.OpenLdap";
60654fc587aSNagaraju Goruganti                 searchString = "openldap";
607ab828d7cSRatan Gupta             }
608ab828d7cSRatan Gupta             else if (ldapType == "ActiveDirectory")
609ab828d7cSRatan Gupta             {
61054fc587aSNagaraju Goruganti                 ldapDbusType =
6110fda0f12SGeorge Liu                     "xyz.openbmc_project.User.Ldap.Config.Type.ActiveDirectory";
61254fc587aSNagaraju Goruganti                 searchString = "active_directory";
613ab828d7cSRatan Gupta             }
614ab828d7cSRatan Gupta             else
615ab828d7cSRatan Gupta             {
61662598e31SEd Tanous                 BMCWEB_LOG_ERROR("Can't get the DbusType for the given type={}",
61762598e31SEd Tanous                                  ldapType);
618ab828d7cSRatan Gupta                 callback(false, confData, ldapType);
619ab828d7cSRatan Gupta                 return;
620ab828d7cSRatan Gupta             }
621ab828d7cSRatan Gupta 
622ab828d7cSRatan Gupta             std::string ldapEnableInterfaceStr = ldapEnableInterface;
623ab828d7cSRatan Gupta             std::string ldapConfigInterfaceStr = ldapConfigInterface;
624ab828d7cSRatan Gupta 
6256973a582SRatan Gupta             for (const auto& object : ldapObjects)
6266973a582SRatan Gupta             {
62754fc587aSNagaraju Goruganti                 // let's find the object whose ldap type is equal to the
62854fc587aSNagaraju Goruganti                 // given type
629002d39b4SEd Tanous                 if (object.first.str.find(searchString) == std::string::npos)
6306973a582SRatan Gupta                 {
631ab828d7cSRatan Gupta                     continue;
632ab828d7cSRatan Gupta                 }
633ab828d7cSRatan Gupta 
6346973a582SRatan Gupta                 for (const auto& interface : object.second)
6356973a582SRatan Gupta                 {
6366973a582SRatan Gupta                     if (interface.first == ldapEnableInterfaceStr)
6376973a582SRatan Gupta                     {
6386973a582SRatan Gupta                         // rest of the properties are string.
6396973a582SRatan Gupta                         for (const auto& property : interface.second)
6406973a582SRatan Gupta                         {
6416973a582SRatan Gupta                             if (property.first == "Enabled")
6426973a582SRatan Gupta                             {
6436973a582SRatan Gupta                                 const bool* value =
6446973a582SRatan Gupta                                     std::get_if<bool>(&property.second);
6456973a582SRatan Gupta                                 if (value == nullptr)
6466973a582SRatan Gupta                                 {
6476973a582SRatan Gupta                                     continue;
6486973a582SRatan Gupta                                 }
6496973a582SRatan Gupta                                 confData.serviceEnabled = *value;
6506973a582SRatan Gupta                                 break;
6516973a582SRatan Gupta                             }
6526973a582SRatan Gupta                         }
6536973a582SRatan Gupta                     }
6546973a582SRatan Gupta                     else if (interface.first == ldapConfigInterfaceStr)
6556973a582SRatan Gupta                     {
6566973a582SRatan Gupta                         for (const auto& property : interface.second)
6576973a582SRatan Gupta                         {
658271584abSEd Tanous                             const std::string* strValue =
659002d39b4SEd Tanous                                 std::get_if<std::string>(&property.second);
660271584abSEd Tanous                             if (strValue == nullptr)
6616973a582SRatan Gupta                             {
6626973a582SRatan Gupta                                 continue;
6636973a582SRatan Gupta                             }
6646973a582SRatan Gupta                             if (property.first == "LDAPServerURI")
6656973a582SRatan Gupta                             {
666271584abSEd Tanous                                 confData.uri = *strValue;
6676973a582SRatan Gupta                             }
6686973a582SRatan Gupta                             else if (property.first == "LDAPBindDN")
6696973a582SRatan Gupta                             {
670271584abSEd Tanous                                 confData.bindDN = *strValue;
6716973a582SRatan Gupta                             }
6726973a582SRatan Gupta                             else if (property.first == "LDAPBaseDN")
6736973a582SRatan Gupta                             {
674271584abSEd Tanous                                 confData.baseDN = *strValue;
6756973a582SRatan Gupta                             }
676002d39b4SEd Tanous                             else if (property.first == "LDAPSearchScope")
6776973a582SRatan Gupta                             {
678271584abSEd Tanous                                 confData.searchScope = *strValue;
6796973a582SRatan Gupta                             }
680002d39b4SEd Tanous                             else if (property.first == "GroupNameAttribute")
6816973a582SRatan Gupta                             {
682271584abSEd Tanous                                 confData.groupAttribute = *strValue;
6836973a582SRatan Gupta                             }
684002d39b4SEd Tanous                             else if (property.first == "UserNameAttribute")
6856973a582SRatan Gupta                             {
686271584abSEd Tanous                                 confData.userNameAttribute = *strValue;
6876973a582SRatan Gupta                             }
68854fc587aSNagaraju Goruganti                             else if (property.first == "LDAPType")
689ab828d7cSRatan Gupta                             {
690271584abSEd Tanous                                 confData.serverType = *strValue;
69154fc587aSNagaraju Goruganti                             }
69254fc587aSNagaraju Goruganti                         }
69354fc587aSNagaraju Goruganti                     }
694002d39b4SEd Tanous                     else if (interface.first ==
6950fda0f12SGeorge Liu                              "xyz.openbmc_project.User.PrivilegeMapperEntry")
69654fc587aSNagaraju Goruganti                     {
69754fc587aSNagaraju Goruganti                         LDAPRoleMapData roleMapData{};
69854fc587aSNagaraju Goruganti                         for (const auto& property : interface.second)
69954fc587aSNagaraju Goruganti                         {
700271584abSEd Tanous                             const std::string* strValue =
701002d39b4SEd Tanous                                 std::get_if<std::string>(&property.second);
70254fc587aSNagaraju Goruganti 
703271584abSEd Tanous                             if (strValue == nullptr)
70454fc587aSNagaraju Goruganti                             {
70554fc587aSNagaraju Goruganti                                 continue;
70654fc587aSNagaraju Goruganti                             }
70754fc587aSNagaraju Goruganti 
70854fc587aSNagaraju Goruganti                             if (property.first == "GroupName")
70954fc587aSNagaraju Goruganti                             {
710271584abSEd Tanous                                 roleMapData.groupName = *strValue;
71154fc587aSNagaraju Goruganti                             }
71254fc587aSNagaraju Goruganti                             else if (property.first == "Privilege")
71354fc587aSNagaraju Goruganti                             {
714271584abSEd Tanous                                 roleMapData.privilege = *strValue;
71554fc587aSNagaraju Goruganti                             }
71654fc587aSNagaraju Goruganti                         }
71754fc587aSNagaraju Goruganti 
718002d39b4SEd Tanous                         confData.groupRoleList.emplace_back(object.first.str,
719002d39b4SEd Tanous                                                             roleMapData);
72054fc587aSNagaraju Goruganti                     }
72154fc587aSNagaraju Goruganti                 }
72254fc587aSNagaraju Goruganti             }
723ab828d7cSRatan Gupta             callback(true, confData, ldapType);
7245eb468daSGeorge Liu         });
7252b73119cSGeorge Liu     });
7266973a582SRatan Gupta }
7276973a582SRatan Gupta 
7288a07d286SRatan Gupta /**
7298a07d286SRatan Gupta  * @brief parses the authentication section under the LDAP
7308a07d286SRatan Gupta  * @param input JSON data
7318a07d286SRatan Gupta  * @param asyncResp pointer to the JSON response
7328a07d286SRatan Gupta  * @param userName  userName to be filled from the given JSON.
7338a07d286SRatan Gupta  * @param password  password to be filled from the given JSON.
7348a07d286SRatan Gupta  */
7354f48d5f6SEd Tanous inline void parseLDAPAuthenticationJson(
7366c51eab1SEd Tanous     nlohmann::json input, const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
7376c51eab1SEd Tanous     std::optional<std::string>& username, std::optional<std::string>& password)
7388a07d286SRatan Gupta {
7398a07d286SRatan Gupta     std::optional<std::string> authType;
7408a07d286SRatan Gupta 
7418a07d286SRatan Gupta     if (!json_util::readJson(input, asyncResp->res, "AuthenticationType",
7428a07d286SRatan Gupta                              authType, "Username", username, "Password",
7438a07d286SRatan Gupta                              password))
7448a07d286SRatan Gupta     {
7458a07d286SRatan Gupta         return;
7468a07d286SRatan Gupta     }
7478a07d286SRatan Gupta     if (!authType)
7488a07d286SRatan Gupta     {
7498a07d286SRatan Gupta         return;
7508a07d286SRatan Gupta     }
7518a07d286SRatan Gupta     if (*authType != "UsernameAndPassword")
7528a07d286SRatan Gupta     {
7538a07d286SRatan Gupta         messages::propertyValueNotInList(asyncResp->res, *authType,
7548a07d286SRatan Gupta                                          "AuthenticationType");
7558a07d286SRatan Gupta         return;
7568a07d286SRatan Gupta     }
7578a07d286SRatan Gupta }
7588a07d286SRatan Gupta /**
7598a07d286SRatan Gupta  * @brief parses the LDAPService section under the LDAP
7608a07d286SRatan Gupta  * @param input JSON data
7618a07d286SRatan Gupta  * @param asyncResp pointer to the JSON response
7628a07d286SRatan Gupta  * @param baseDNList baseDN to be filled from the given JSON.
7638a07d286SRatan Gupta  * @param userNameAttribute  userName to be filled from the given JSON.
7648a07d286SRatan Gupta  * @param groupaAttribute  password to be filled from the given JSON.
7658a07d286SRatan Gupta  */
7668a07d286SRatan Gupta 
7674f48d5f6SEd Tanous inline void
7684f48d5f6SEd Tanous     parseLDAPServiceJson(nlohmann::json input,
7698d1b46d7Szhanghch05                          const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
7708a07d286SRatan Gupta                          std::optional<std::vector<std::string>>& baseDNList,
7718a07d286SRatan Gupta                          std::optional<std::string>& userNameAttribute,
7728a07d286SRatan Gupta                          std::optional<std::string>& groupsAttribute)
7738a07d286SRatan Gupta {
7748a07d286SRatan Gupta     std::optional<nlohmann::json> searchSettings;
7758a07d286SRatan Gupta 
7768a07d286SRatan Gupta     if (!json_util::readJson(input, asyncResp->res, "SearchSettings",
7778a07d286SRatan Gupta                              searchSettings))
7788a07d286SRatan Gupta     {
7798a07d286SRatan Gupta         return;
7808a07d286SRatan Gupta     }
7818a07d286SRatan Gupta     if (!searchSettings)
7828a07d286SRatan Gupta     {
7838a07d286SRatan Gupta         return;
7848a07d286SRatan Gupta     }
7858a07d286SRatan Gupta     if (!json_util::readJson(*searchSettings, asyncResp->res,
7868a07d286SRatan Gupta                              "BaseDistinguishedNames", baseDNList,
7878a07d286SRatan Gupta                              "UsernameAttribute", userNameAttribute,
7888a07d286SRatan Gupta                              "GroupsAttribute", groupsAttribute))
7898a07d286SRatan Gupta     {
7908a07d286SRatan Gupta         return;
7918a07d286SRatan Gupta     }
7928a07d286SRatan Gupta }
7938a07d286SRatan Gupta /**
7948a07d286SRatan Gupta  * @brief updates the LDAP server address and updates the
7958a07d286SRatan Gupta           json response with the new value.
7968a07d286SRatan Gupta  * @param serviceAddressList address to be updated.
7978a07d286SRatan Gupta  * @param asyncResp pointer to the JSON response
7988a07d286SRatan Gupta  * @param ldapServerElementName Type of LDAP
7998a07d286SRatan Gupta  server(openLDAP/ActiveDirectory)
8008a07d286SRatan Gupta  */
8018a07d286SRatan Gupta 
8024f48d5f6SEd Tanous inline void handleServiceAddressPatch(
8038a07d286SRatan Gupta     const std::vector<std::string>& serviceAddressList,
8048d1b46d7Szhanghch05     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
8058a07d286SRatan Gupta     const std::string& ldapServerElementName,
8068a07d286SRatan Gupta     const std::string& ldapConfigObject)
8078a07d286SRatan Gupta {
8089ae226faSGeorge Liu     sdbusplus::asio::setProperty(
8099ae226faSGeorge Liu         *crow::connections::systemBus, ldapDbusService, ldapConfigObject,
8109ae226faSGeorge Liu         ldapConfigInterface, "LDAPServerURI", serviceAddressList.front(),
8117a543894SPatrick Williams         [asyncResp, ldapServerElementName, serviceAddressList](
8127a543894SPatrick Williams             const boost::system::error_code& ec, sdbusplus::message_t& msg) {
8138a07d286SRatan Gupta         if (ec)
8148a07d286SRatan Gupta         {
81525e055a3SRavi Teja             const sd_bus_error* dbusError = msg.get_error();
81625e055a3SRavi Teja             if ((dbusError != nullptr) &&
81725e055a3SRavi Teja                 (dbusError->name ==
81825e055a3SRavi Teja                  std::string_view(
81925e055a3SRavi Teja                      "xyz.openbmc_project.Common.Error.InvalidArgument")))
82025e055a3SRavi Teja             {
82162598e31SEd Tanous                 BMCWEB_LOG_WARNING(
82262598e31SEd Tanous                     "Error Occurred in updating the service address");
82325e055a3SRavi Teja                 messages::propertyValueIncorrect(asyncResp->res,
82425e055a3SRavi Teja                                                  "ServiceAddresses",
82525e055a3SRavi Teja                                                  serviceAddressList.front());
82625e055a3SRavi Teja                 return;
82725e055a3SRavi Teja             }
8288a07d286SRatan Gupta             messages::internalError(asyncResp->res);
8298a07d286SRatan Gupta             return;
8308a07d286SRatan Gupta         }
8318a07d286SRatan Gupta         std::vector<std::string> modifiedserviceAddressList = {
8328a07d286SRatan Gupta             serviceAddressList.front()};
833002d39b4SEd Tanous         asyncResp->res.jsonValue[ldapServerElementName]["ServiceAddresses"] =
8348a07d286SRatan Gupta             modifiedserviceAddressList;
8358a07d286SRatan Gupta         if ((serviceAddressList).size() > 1)
8368a07d286SRatan Gupta         {
837002d39b4SEd Tanous             messages::propertyValueModified(asyncResp->res, "ServiceAddresses",
8388a07d286SRatan Gupta                                             serviceAddressList.front());
8398a07d286SRatan Gupta         }
84062598e31SEd Tanous         BMCWEB_LOG_DEBUG("Updated the service address");
8419ae226faSGeorge Liu     });
8428a07d286SRatan Gupta }
8438a07d286SRatan Gupta /**
8448a07d286SRatan Gupta  * @brief updates the LDAP Bind DN and updates the
8458a07d286SRatan Gupta           json response with the new value.
8468a07d286SRatan Gupta  * @param username name of the user which needs to be updated.
8478a07d286SRatan Gupta  * @param asyncResp pointer to the JSON response
8488a07d286SRatan Gupta  * @param ldapServerElementName Type of LDAP
8498a07d286SRatan Gupta  server(openLDAP/ActiveDirectory)
8508a07d286SRatan Gupta  */
8518a07d286SRatan Gupta 
8524f48d5f6SEd Tanous inline void
8534f48d5f6SEd Tanous     handleUserNamePatch(const std::string& username,
8548d1b46d7Szhanghch05                         const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
8558a07d286SRatan Gupta                         const std::string& ldapServerElementName,
8568a07d286SRatan Gupta                         const std::string& ldapConfigObject)
8578a07d286SRatan Gupta {
8589ae226faSGeorge Liu     sdbusplus::asio::setProperty(*crow::connections::systemBus, ldapDbusService,
8599ae226faSGeorge Liu                                  ldapConfigObject, ldapConfigInterface,
8609ae226faSGeorge Liu                                  "LDAPBindDN", username,
8619ae226faSGeorge Liu                                  [asyncResp, username, ldapServerElementName](
8629ae226faSGeorge Liu                                      const boost::system::error_code& ec) {
8638a07d286SRatan Gupta         if (ec)
8648a07d286SRatan Gupta         {
86562598e31SEd Tanous             BMCWEB_LOG_DEBUG("Error occurred in updating the username");
8668a07d286SRatan Gupta             messages::internalError(asyncResp->res);
8678a07d286SRatan Gupta             return;
8688a07d286SRatan Gupta         }
86989492a15SPatrick Williams         asyncResp->res.jsonValue[ldapServerElementName]["Authentication"]
87089492a15SPatrick Williams                                 ["Username"] = username;
87162598e31SEd Tanous         BMCWEB_LOG_DEBUG("Updated the username");
8729ae226faSGeorge Liu     });
8738a07d286SRatan Gupta }
8748a07d286SRatan Gupta 
8758a07d286SRatan Gupta /**
8768a07d286SRatan Gupta  * @brief updates the LDAP password
8778a07d286SRatan Gupta  * @param password : ldap password which needs to be updated.
8788a07d286SRatan Gupta  * @param asyncResp pointer to the JSON response
8798a07d286SRatan Gupta  * @param ldapServerElementName Type of LDAP
8808a07d286SRatan Gupta  *        server(openLDAP/ActiveDirectory)
8818a07d286SRatan Gupta  */
8828a07d286SRatan Gupta 
8834f48d5f6SEd Tanous inline void
8844f48d5f6SEd Tanous     handlePasswordPatch(const std::string& password,
8858d1b46d7Szhanghch05                         const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
8868a07d286SRatan Gupta                         const std::string& ldapServerElementName,
8878a07d286SRatan Gupta                         const std::string& ldapConfigObject)
8888a07d286SRatan Gupta {
8899ae226faSGeorge Liu     sdbusplus::asio::setProperty(*crow::connections::systemBus, ldapDbusService,
8909ae226faSGeorge Liu                                  ldapConfigObject, ldapConfigInterface,
8919ae226faSGeorge Liu                                  "LDAPBindDNPassword", password,
8929ae226faSGeorge Liu                                  [asyncResp, password, ldapServerElementName](
8939ae226faSGeorge Liu                                      const boost::system::error_code& ec) {
8948a07d286SRatan Gupta         if (ec)
8958a07d286SRatan Gupta         {
89662598e31SEd Tanous             BMCWEB_LOG_DEBUG("Error occurred in updating the password");
8978a07d286SRatan Gupta             messages::internalError(asyncResp->res);
8988a07d286SRatan Gupta             return;
8998a07d286SRatan Gupta         }
90089492a15SPatrick Williams         asyncResp->res.jsonValue[ldapServerElementName]["Authentication"]
90189492a15SPatrick Williams                                 ["Password"] = "";
90262598e31SEd Tanous         BMCWEB_LOG_DEBUG("Updated the password");
9039ae226faSGeorge Liu     });
9048a07d286SRatan Gupta }
9058a07d286SRatan Gupta 
9068a07d286SRatan Gupta /**
9078a07d286SRatan Gupta  * @brief updates the LDAP BaseDN and updates the
9088a07d286SRatan Gupta           json response with the new value.
9098a07d286SRatan Gupta  * @param baseDNList baseDN list which needs to be updated.
9108a07d286SRatan Gupta  * @param asyncResp pointer to the JSON response
9118a07d286SRatan Gupta  * @param ldapServerElementName Type of LDAP
9128a07d286SRatan Gupta  server(openLDAP/ActiveDirectory)
9138a07d286SRatan Gupta  */
9148a07d286SRatan Gupta 
9154f48d5f6SEd Tanous inline void
9164f48d5f6SEd Tanous     handleBaseDNPatch(const std::vector<std::string>& baseDNList,
9178d1b46d7Szhanghch05                       const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
9188a07d286SRatan Gupta                       const std::string& ldapServerElementName,
9198a07d286SRatan Gupta                       const std::string& ldapConfigObject)
9208a07d286SRatan Gupta {
9219ae226faSGeorge Liu     sdbusplus::asio::setProperty(*crow::connections::systemBus, ldapDbusService,
9229ae226faSGeorge Liu                                  ldapConfigObject, ldapConfigInterface,
9239ae226faSGeorge Liu                                  "LDAPBaseDN", baseDNList.front(),
9249ae226faSGeorge Liu                                  [asyncResp, baseDNList, ldapServerElementName](
9259ae226faSGeorge Liu                                      const boost::system::error_code& ec,
9267a543894SPatrick Williams                                      const sdbusplus::message_t& msg) {
9278a07d286SRatan Gupta         if (ec)
9288a07d286SRatan Gupta         {
92962598e31SEd Tanous             BMCWEB_LOG_DEBUG("Error Occurred in Updating the base DN");
93025e055a3SRavi Teja             const sd_bus_error* dbusError = msg.get_error();
93125e055a3SRavi Teja             if ((dbusError != nullptr) &&
93225e055a3SRavi Teja                 (dbusError->name ==
93325e055a3SRavi Teja                  std::string_view(
93425e055a3SRavi Teja                      "xyz.openbmc_project.Common.Error.InvalidArgument")))
93525e055a3SRavi Teja             {
93625e055a3SRavi Teja                 messages::propertyValueIncorrect(asyncResp->res,
93725e055a3SRavi Teja                                                  "BaseDistinguishedNames",
93825e055a3SRavi Teja                                                  baseDNList.front());
93925e055a3SRavi Teja                 return;
94025e055a3SRavi Teja             }
9418a07d286SRatan Gupta             messages::internalError(asyncResp->res);
9428a07d286SRatan Gupta             return;
9438a07d286SRatan Gupta         }
944002d39b4SEd Tanous         auto& serverTypeJson = asyncResp->res.jsonValue[ldapServerElementName];
9458a07d286SRatan Gupta         auto& searchSettingsJson =
9468a07d286SRatan Gupta             serverTypeJson["LDAPService"]["SearchSettings"];
9476c51eab1SEd Tanous         std::vector<std::string> modifiedBaseDNList = {baseDNList.front()};
9486c51eab1SEd Tanous         searchSettingsJson["BaseDistinguishedNames"] = modifiedBaseDNList;
9498a07d286SRatan Gupta         if (baseDNList.size() > 1)
9508a07d286SRatan Gupta         {
951002d39b4SEd Tanous             messages::propertyValueModified(
952002d39b4SEd Tanous                 asyncResp->res, "BaseDistinguishedNames", baseDNList.front());
9538a07d286SRatan Gupta         }
95462598e31SEd Tanous         BMCWEB_LOG_DEBUG("Updated the base DN");
9559ae226faSGeorge Liu     });
9568a07d286SRatan Gupta }
9578a07d286SRatan Gupta /**
9588a07d286SRatan Gupta  * @brief updates the LDAP user name attribute and updates the
9598a07d286SRatan Gupta           json response with the new value.
9608a07d286SRatan Gupta  * @param userNameAttribute attribute to be updated.
9618a07d286SRatan Gupta  * @param asyncResp pointer to the JSON response
9628a07d286SRatan Gupta  * @param ldapServerElementName Type of LDAP
9638a07d286SRatan Gupta  server(openLDAP/ActiveDirectory)
9648a07d286SRatan Gupta  */
9658a07d286SRatan Gupta 
9664f48d5f6SEd Tanous inline void
9674f48d5f6SEd Tanous     handleUserNameAttrPatch(const std::string& userNameAttribute,
9688d1b46d7Szhanghch05                             const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
9698a07d286SRatan Gupta                             const std::string& ldapServerElementName,
9708a07d286SRatan Gupta                             const std::string& ldapConfigObject)
9718a07d286SRatan Gupta {
9729ae226faSGeorge Liu     sdbusplus::asio::setProperty(
9739ae226faSGeorge Liu         *crow::connections::systemBus, ldapDbusService, ldapConfigObject,
9749ae226faSGeorge Liu         ldapConfigInterface, "UserNameAttribute", userNameAttribute,
9758a07d286SRatan Gupta         [asyncResp, userNameAttribute,
9765e7e2dc5SEd Tanous          ldapServerElementName](const boost::system::error_code& ec) {
9778a07d286SRatan Gupta         if (ec)
9788a07d286SRatan Gupta         {
97962598e31SEd Tanous             BMCWEB_LOG_DEBUG("Error Occurred in Updating the "
98062598e31SEd Tanous                              "username attribute");
9818a07d286SRatan Gupta             messages::internalError(asyncResp->res);
9828a07d286SRatan Gupta             return;
9838a07d286SRatan Gupta         }
984002d39b4SEd Tanous         auto& serverTypeJson = asyncResp->res.jsonValue[ldapServerElementName];
9858a07d286SRatan Gupta         auto& searchSettingsJson =
9868a07d286SRatan Gupta             serverTypeJson["LDAPService"]["SearchSettings"];
9878a07d286SRatan Gupta         searchSettingsJson["UsernameAttribute"] = userNameAttribute;
98862598e31SEd Tanous         BMCWEB_LOG_DEBUG("Updated the user name attr.");
9899ae226faSGeorge Liu     });
9908a07d286SRatan Gupta }
9918a07d286SRatan Gupta /**
9928a07d286SRatan Gupta  * @brief updates the LDAP group attribute and updates the
9938a07d286SRatan Gupta           json response with the new value.
9948a07d286SRatan Gupta  * @param groupsAttribute attribute to be updated.
9958a07d286SRatan Gupta  * @param asyncResp pointer to the JSON response
9968a07d286SRatan Gupta  * @param ldapServerElementName Type of LDAP
9978a07d286SRatan Gupta  server(openLDAP/ActiveDirectory)
9988a07d286SRatan Gupta  */
9998a07d286SRatan Gupta 
10004f48d5f6SEd Tanous inline void handleGroupNameAttrPatch(
10018d1b46d7Szhanghch05     const std::string& groupsAttribute,
10028d1b46d7Szhanghch05     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
10038a07d286SRatan Gupta     const std::string& ldapServerElementName,
10048a07d286SRatan Gupta     const std::string& ldapConfigObject)
10058a07d286SRatan Gupta {
10069ae226faSGeorge Liu     sdbusplus::asio::setProperty(
10079ae226faSGeorge Liu         *crow::connections::systemBus, ldapDbusService, ldapConfigObject,
10089ae226faSGeorge Liu         ldapConfigInterface, "GroupNameAttribute", groupsAttribute,
10098a07d286SRatan Gupta         [asyncResp, groupsAttribute,
10105e7e2dc5SEd Tanous          ldapServerElementName](const boost::system::error_code& ec) {
10118a07d286SRatan Gupta         if (ec)
10128a07d286SRatan Gupta         {
101362598e31SEd Tanous             BMCWEB_LOG_DEBUG("Error Occurred in Updating the "
101462598e31SEd Tanous                              "groupname attribute");
10158a07d286SRatan Gupta             messages::internalError(asyncResp->res);
10168a07d286SRatan Gupta             return;
10178a07d286SRatan Gupta         }
1018002d39b4SEd Tanous         auto& serverTypeJson = asyncResp->res.jsonValue[ldapServerElementName];
10198a07d286SRatan Gupta         auto& searchSettingsJson =
10208a07d286SRatan Gupta             serverTypeJson["LDAPService"]["SearchSettings"];
10218a07d286SRatan Gupta         searchSettingsJson["GroupsAttribute"] = groupsAttribute;
102262598e31SEd Tanous         BMCWEB_LOG_DEBUG("Updated the groupname attr");
10239ae226faSGeorge Liu     });
10248a07d286SRatan Gupta }
10258a07d286SRatan Gupta /**
10268a07d286SRatan Gupta  * @brief updates the LDAP service enable and updates the
10278a07d286SRatan Gupta           json response with the new value.
10288a07d286SRatan Gupta  * @param input JSON data.
10298a07d286SRatan Gupta  * @param asyncResp pointer to the JSON response
10308a07d286SRatan Gupta  * @param ldapServerElementName Type of LDAP
10318a07d286SRatan Gupta  server(openLDAP/ActiveDirectory)
10328a07d286SRatan Gupta  */
10338a07d286SRatan Gupta 
10344f48d5f6SEd Tanous inline void handleServiceEnablePatch(
10356c51eab1SEd Tanous     bool serviceEnabled, const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
10368a07d286SRatan Gupta     const std::string& ldapServerElementName,
10378a07d286SRatan Gupta     const std::string& ldapConfigObject)
10388a07d286SRatan Gupta {
10399ae226faSGeorge Liu     sdbusplus::asio::setProperty(
10409ae226faSGeorge Liu         *crow::connections::systemBus, ldapDbusService, ldapConfigObject,
10419ae226faSGeorge Liu         ldapEnableInterface, "Enabled", serviceEnabled,
10428a07d286SRatan Gupta         [asyncResp, serviceEnabled,
10435e7e2dc5SEd Tanous          ldapServerElementName](const boost::system::error_code& ec) {
10448a07d286SRatan Gupta         if (ec)
10458a07d286SRatan Gupta         {
104662598e31SEd Tanous             BMCWEB_LOG_DEBUG("Error Occurred in Updating the service enable");
10478a07d286SRatan Gupta             messages::internalError(asyncResp->res);
10488a07d286SRatan Gupta             return;
10498a07d286SRatan Gupta         }
10506c51eab1SEd Tanous         asyncResp->res.jsonValue[ldapServerElementName]["ServiceEnabled"] =
10518a07d286SRatan Gupta             serviceEnabled;
105262598e31SEd Tanous         BMCWEB_LOG_DEBUG("Updated Service enable = {}", serviceEnabled);
10539ae226faSGeorge Liu     });
10548a07d286SRatan Gupta }
10558a07d286SRatan Gupta 
10564f48d5f6SEd Tanous inline void
10574f48d5f6SEd Tanous     handleAuthMethodsPatch(nlohmann::json& input,
10588d1b46d7Szhanghch05                            const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
105978158631SZbigniew Kurzynski {
106078158631SZbigniew Kurzynski     std::optional<bool> basicAuth;
106178158631SZbigniew Kurzynski     std::optional<bool> cookie;
106278158631SZbigniew Kurzynski     std::optional<bool> sessionToken;
106378158631SZbigniew Kurzynski     std::optional<bool> xToken;
1064501f1e58SZbigniew Kurzynski     std::optional<bool> tls;
106578158631SZbigniew Kurzynski 
106678158631SZbigniew Kurzynski     if (!json_util::readJson(input, asyncResp->res, "BasicAuth", basicAuth,
106778158631SZbigniew Kurzynski                              "Cookie", cookie, "SessionToken", sessionToken,
1068501f1e58SZbigniew Kurzynski                              "XToken", xToken, "TLS", tls))
106978158631SZbigniew Kurzynski     {
107062598e31SEd Tanous         BMCWEB_LOG_ERROR("Cannot read values from AuthMethod tag");
107178158631SZbigniew Kurzynski         return;
107278158631SZbigniew Kurzynski     }
107378158631SZbigniew Kurzynski 
107478158631SZbigniew Kurzynski     // Make a copy of methods configuration
107552cc112dSEd Tanous     persistent_data::AuthConfigMethods authMethodsConfig =
107652cc112dSEd Tanous         persistent_data::SessionStore::getInstance().getAuthMethodsConfig();
107778158631SZbigniew Kurzynski 
107878158631SZbigniew Kurzynski     if (basicAuth)
107978158631SZbigniew Kurzynski     {
1080f16f6263SAlan Kuo #ifndef BMCWEB_ENABLE_BASIC_AUTHENTICATION
1081f16f6263SAlan Kuo         messages::actionNotSupported(
10820fda0f12SGeorge Liu             asyncResp->res,
10830fda0f12SGeorge Liu             "Setting BasicAuth when basic-auth feature is disabled");
1084f16f6263SAlan Kuo         return;
1085f16f6263SAlan Kuo #endif
108678158631SZbigniew Kurzynski         authMethodsConfig.basic = *basicAuth;
108778158631SZbigniew Kurzynski     }
108878158631SZbigniew Kurzynski 
108978158631SZbigniew Kurzynski     if (cookie)
109078158631SZbigniew Kurzynski     {
1091f16f6263SAlan Kuo #ifndef BMCWEB_ENABLE_COOKIE_AUTHENTICATION
10920fda0f12SGeorge Liu         messages::actionNotSupported(
10930fda0f12SGeorge Liu             asyncResp->res,
10940fda0f12SGeorge Liu             "Setting Cookie when cookie-auth feature is disabled");
1095f16f6263SAlan Kuo         return;
1096f16f6263SAlan Kuo #endif
109778158631SZbigniew Kurzynski         authMethodsConfig.cookie = *cookie;
109878158631SZbigniew Kurzynski     }
109978158631SZbigniew Kurzynski 
110078158631SZbigniew Kurzynski     if (sessionToken)
110178158631SZbigniew Kurzynski     {
1102f16f6263SAlan Kuo #ifndef BMCWEB_ENABLE_SESSION_AUTHENTICATION
1103f16f6263SAlan Kuo         messages::actionNotSupported(
11040fda0f12SGeorge Liu             asyncResp->res,
11050fda0f12SGeorge Liu             "Setting SessionToken when session-auth feature is disabled");
1106f16f6263SAlan Kuo         return;
1107f16f6263SAlan Kuo #endif
110878158631SZbigniew Kurzynski         authMethodsConfig.sessionToken = *sessionToken;
110978158631SZbigniew Kurzynski     }
111078158631SZbigniew Kurzynski 
111178158631SZbigniew Kurzynski     if (xToken)
111278158631SZbigniew Kurzynski     {
1113f16f6263SAlan Kuo #ifndef BMCWEB_ENABLE_XTOKEN_AUTHENTICATION
11140fda0f12SGeorge Liu         messages::actionNotSupported(
11150fda0f12SGeorge Liu             asyncResp->res,
11160fda0f12SGeorge Liu             "Setting XToken when xtoken-auth feature is disabled");
1117f16f6263SAlan Kuo         return;
1118f16f6263SAlan Kuo #endif
111978158631SZbigniew Kurzynski         authMethodsConfig.xtoken = *xToken;
112078158631SZbigniew Kurzynski     }
112178158631SZbigniew Kurzynski 
1122501f1e58SZbigniew Kurzynski     if (tls)
1123501f1e58SZbigniew Kurzynski     {
1124f16f6263SAlan Kuo #ifndef BMCWEB_ENABLE_MUTUAL_TLS_AUTHENTICATION
11250fda0f12SGeorge Liu         messages::actionNotSupported(
11260fda0f12SGeorge Liu             asyncResp->res,
11270fda0f12SGeorge Liu             "Setting TLS when mutual-tls-auth feature is disabled");
1128f16f6263SAlan Kuo         return;
1129f16f6263SAlan Kuo #endif
1130501f1e58SZbigniew Kurzynski         authMethodsConfig.tls = *tls;
1131501f1e58SZbigniew Kurzynski     }
1132501f1e58SZbigniew Kurzynski 
113378158631SZbigniew Kurzynski     if (!authMethodsConfig.basic && !authMethodsConfig.cookie &&
1134501f1e58SZbigniew Kurzynski         !authMethodsConfig.sessionToken && !authMethodsConfig.xtoken &&
1135501f1e58SZbigniew Kurzynski         !authMethodsConfig.tls)
113678158631SZbigniew Kurzynski     {
113778158631SZbigniew Kurzynski         // Do not allow user to disable everything
113878158631SZbigniew Kurzynski         messages::actionNotSupported(asyncResp->res,
113978158631SZbigniew Kurzynski                                      "of disabling all available methods");
114078158631SZbigniew Kurzynski         return;
114178158631SZbigniew Kurzynski     }
114278158631SZbigniew Kurzynski 
114352cc112dSEd Tanous     persistent_data::SessionStore::getInstance().updateAuthMethodsConfig(
114452cc112dSEd Tanous         authMethodsConfig);
114578158631SZbigniew Kurzynski     // Save configuration immediately
114652cc112dSEd Tanous     persistent_data::getConfig().writeData();
114778158631SZbigniew Kurzynski 
114878158631SZbigniew Kurzynski     messages::success(asyncResp->res);
114978158631SZbigniew Kurzynski }
115078158631SZbigniew Kurzynski 
11518a07d286SRatan Gupta /**
11528a07d286SRatan Gupta  * @brief Get the required values from the given JSON, validates the
11538a07d286SRatan Gupta  *        value and create the LDAP config object.
11548a07d286SRatan Gupta  * @param input JSON data
11558a07d286SRatan Gupta  * @param asyncResp pointer to the JSON response
11568a07d286SRatan Gupta  * @param serverType Type of LDAP server(openLDAP/ActiveDirectory)
11578a07d286SRatan Gupta  */
11588a07d286SRatan Gupta 
11596c51eab1SEd Tanous inline void handleLDAPPatch(nlohmann::json& input,
11608d1b46d7Szhanghch05                             const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
11618a07d286SRatan Gupta                             const std::string& serverType)
11628a07d286SRatan Gupta {
1163eb2bbe56SRatan Gupta     std::string dbusObjectPath;
1164eb2bbe56SRatan Gupta     if (serverType == "ActiveDirectory")
1165eb2bbe56SRatan Gupta     {
11662c70f800SEd Tanous         dbusObjectPath = adConfigObject;
1167eb2bbe56SRatan Gupta     }
1168eb2bbe56SRatan Gupta     else if (serverType == "LDAP")
1169eb2bbe56SRatan Gupta     {
117023a21a1cSEd Tanous         dbusObjectPath = ldapConfigObjectName;
1171eb2bbe56SRatan Gupta     }
1172cb13a392SEd Tanous     else
1173cb13a392SEd Tanous     {
1174cb13a392SEd Tanous         return;
1175cb13a392SEd Tanous     }
1176eb2bbe56SRatan Gupta 
11778a07d286SRatan Gupta     std::optional<nlohmann::json> authentication;
11788a07d286SRatan Gupta     std::optional<nlohmann::json> ldapService;
11798a07d286SRatan Gupta     std::optional<std::vector<std::string>> serviceAddressList;
11808a07d286SRatan Gupta     std::optional<bool> serviceEnabled;
11818a07d286SRatan Gupta     std::optional<std::vector<std::string>> baseDNList;
11828a07d286SRatan Gupta     std::optional<std::string> userNameAttribute;
11838a07d286SRatan Gupta     std::optional<std::string> groupsAttribute;
11848a07d286SRatan Gupta     std::optional<std::string> userName;
11858a07d286SRatan Gupta     std::optional<std::string> password;
118606785244SRatan Gupta     std::optional<std::vector<nlohmann::json>> remoteRoleMapData;
11878a07d286SRatan Gupta 
11888a07d286SRatan Gupta     if (!json_util::readJson(input, asyncResp->res, "Authentication",
11898a07d286SRatan Gupta                              authentication, "LDAPService", ldapService,
11908a07d286SRatan Gupta                              "ServiceAddresses", serviceAddressList,
119106785244SRatan Gupta                              "ServiceEnabled", serviceEnabled,
119206785244SRatan Gupta                              "RemoteRoleMapping", remoteRoleMapData))
11938a07d286SRatan Gupta     {
11948a07d286SRatan Gupta         return;
11958a07d286SRatan Gupta     }
11968a07d286SRatan Gupta 
11978a07d286SRatan Gupta     if (authentication)
11988a07d286SRatan Gupta     {
11998a07d286SRatan Gupta         parseLDAPAuthenticationJson(*authentication, asyncResp, userName,
12008a07d286SRatan Gupta                                     password);
12018a07d286SRatan Gupta     }
12028a07d286SRatan Gupta     if (ldapService)
12038a07d286SRatan Gupta     {
12048a07d286SRatan Gupta         parseLDAPServiceJson(*ldapService, asyncResp, baseDNList,
12058a07d286SRatan Gupta                              userNameAttribute, groupsAttribute);
12068a07d286SRatan Gupta     }
12078a07d286SRatan Gupta     if (serviceAddressList)
12088a07d286SRatan Gupta     {
120926f6976fSEd Tanous         if (serviceAddressList->empty())
12108a07d286SRatan Gupta         {
1211e2616cc5SEd Tanous             messages::propertyValueNotInList(
1212e2616cc5SEd Tanous                 asyncResp->res, *serviceAddressList, "ServiceAddress");
12138a07d286SRatan Gupta             return;
12148a07d286SRatan Gupta         }
12158a07d286SRatan Gupta     }
12168a07d286SRatan Gupta     if (baseDNList)
12178a07d286SRatan Gupta     {
121826f6976fSEd Tanous         if (baseDNList->empty())
12198a07d286SRatan Gupta         {
1220e2616cc5SEd Tanous             messages::propertyValueNotInList(asyncResp->res, *baseDNList,
12218a07d286SRatan Gupta                                              "BaseDistinguishedNames");
12228a07d286SRatan Gupta             return;
12238a07d286SRatan Gupta         }
12248a07d286SRatan Gupta     }
12258a07d286SRatan Gupta 
12268a07d286SRatan Gupta     // nothing to update, then return
12278a07d286SRatan Gupta     if (!userName && !password && !serviceAddressList && !baseDNList &&
122806785244SRatan Gupta         !userNameAttribute && !groupsAttribute && !serviceEnabled &&
122906785244SRatan Gupta         !remoteRoleMapData)
12308a07d286SRatan Gupta     {
12318a07d286SRatan Gupta         return;
12328a07d286SRatan Gupta     }
12338a07d286SRatan Gupta 
12348a07d286SRatan Gupta     // Get the existing resource first then keep modifying
12358a07d286SRatan Gupta     // whenever any property gets updated.
1236002d39b4SEd Tanous     getLDAPConfigData(
1237002d39b4SEd Tanous         serverType,
1238002d39b4SEd Tanous         [asyncResp, userName, password, baseDNList, userNameAttribute,
1239002d39b4SEd Tanous          groupsAttribute, serviceAddressList, serviceEnabled, dbusObjectPath,
1240002d39b4SEd Tanous          remoteRoleMapData](bool success, const LDAPConfigData& confData,
124123a21a1cSEd Tanous                             const std::string& serverT) {
12428a07d286SRatan Gupta         if (!success)
12438a07d286SRatan Gupta         {
12448a07d286SRatan Gupta             messages::internalError(asyncResp->res);
12458a07d286SRatan Gupta             return;
12468a07d286SRatan Gupta         }
12476c51eab1SEd Tanous         parseLDAPConfigData(asyncResp->res.jsonValue, confData, serverT);
12488a07d286SRatan Gupta         if (confData.serviceEnabled)
12498a07d286SRatan Gupta         {
12508a07d286SRatan Gupta             // Disable the service first and update the rest of
12518a07d286SRatan Gupta             // the properties.
12526c51eab1SEd Tanous             handleServiceEnablePatch(false, asyncResp, serverT, dbusObjectPath);
12538a07d286SRatan Gupta         }
12548a07d286SRatan Gupta 
12558a07d286SRatan Gupta         if (serviceAddressList)
12568a07d286SRatan Gupta         {
12576c51eab1SEd Tanous             handleServiceAddressPatch(*serviceAddressList, asyncResp, serverT,
12586c51eab1SEd Tanous                                       dbusObjectPath);
12598a07d286SRatan Gupta         }
12608a07d286SRatan Gupta         if (userName)
12618a07d286SRatan Gupta         {
12626c51eab1SEd Tanous             handleUserNamePatch(*userName, asyncResp, serverT, dbusObjectPath);
12638a07d286SRatan Gupta         }
12648a07d286SRatan Gupta         if (password)
12658a07d286SRatan Gupta         {
12666c51eab1SEd Tanous             handlePasswordPatch(*password, asyncResp, serverT, dbusObjectPath);
12678a07d286SRatan Gupta         }
12688a07d286SRatan Gupta 
12698a07d286SRatan Gupta         if (baseDNList)
12708a07d286SRatan Gupta         {
12716c51eab1SEd Tanous             handleBaseDNPatch(*baseDNList, asyncResp, serverT, dbusObjectPath);
12728a07d286SRatan Gupta         }
12738a07d286SRatan Gupta         if (userNameAttribute)
12748a07d286SRatan Gupta         {
12756c51eab1SEd Tanous             handleUserNameAttrPatch(*userNameAttribute, asyncResp, serverT,
12766c51eab1SEd Tanous                                     dbusObjectPath);
12778a07d286SRatan Gupta         }
12788a07d286SRatan Gupta         if (groupsAttribute)
12798a07d286SRatan Gupta         {
12806c51eab1SEd Tanous             handleGroupNameAttrPatch(*groupsAttribute, asyncResp, serverT,
12816c51eab1SEd Tanous                                      dbusObjectPath);
12828a07d286SRatan Gupta         }
12838a07d286SRatan Gupta         if (serviceEnabled)
12848a07d286SRatan Gupta         {
12858a07d286SRatan Gupta             // if user has given the value as true then enable
12868a07d286SRatan Gupta             // the service. if user has given false then no-op
12878a07d286SRatan Gupta             // as service is already stopped.
12888a07d286SRatan Gupta             if (*serviceEnabled)
12898a07d286SRatan Gupta             {
12906c51eab1SEd Tanous                 handleServiceEnablePatch(*serviceEnabled, asyncResp, serverT,
12916c51eab1SEd Tanous                                          dbusObjectPath);
12928a07d286SRatan Gupta             }
12938a07d286SRatan Gupta         }
12948a07d286SRatan Gupta         else
12958a07d286SRatan Gupta         {
12968a07d286SRatan Gupta             // if user has not given the service enabled value
12978a07d286SRatan Gupta             // then revert it to the same state as it was
12988a07d286SRatan Gupta             // before.
12998a07d286SRatan Gupta             handleServiceEnablePatch(confData.serviceEnabled, asyncResp,
130023a21a1cSEd Tanous                                      serverT, dbusObjectPath);
13018a07d286SRatan Gupta         }
130206785244SRatan Gupta 
130306785244SRatan Gupta         if (remoteRoleMapData)
130406785244SRatan Gupta         {
13056c51eab1SEd Tanous             handleRoleMapPatch(asyncResp, confData.groupRoleList, serverT,
13066c51eab1SEd Tanous                                *remoteRoleMapData);
130706785244SRatan Gupta         }
13088a07d286SRatan Gupta     });
13098a07d286SRatan Gupta }
1310d4b5443fSEd Tanous 
131158345856SAbhishek Patel inline void updateUserProperties(
131258345856SAbhishek Patel     std::shared_ptr<bmcweb::AsyncResp> asyncResp, const std::string& username,
1313618c14b4SEd Tanous     const std::optional<std::string>& password,
1314618c14b4SEd Tanous     const std::optional<bool>& enabled,
131558345856SAbhishek Patel     const std::optional<std::string>& roleId, const std::optional<bool>& locked,
131658345856SAbhishek Patel     std::optional<std::vector<std::string>> accountTypes, bool userSelf)
13171abe55efSEd Tanous {
1318b477fd44SP Dheeraj Srujan Kumar     sdbusplus::message::object_path tempObjPath(rootUserDbusPath);
1319b477fd44SP Dheeraj Srujan Kumar     tempObjPath /= username;
1320b477fd44SP Dheeraj Srujan Kumar     std::string dbusObjectPath(tempObjPath);
13216c51eab1SEd Tanous 
13226c51eab1SEd Tanous     dbus::utility::checkDbusPathExists(
1323618c14b4SEd Tanous         dbusObjectPath, [dbusObjectPath, username, password, roleId, enabled,
132458345856SAbhishek Patel                          locked, accountTypes(std::move(accountTypes)),
132558345856SAbhishek Patel                          userSelf, asyncResp{std::move(asyncResp)}](int rc) {
1326e662eae8SEd Tanous         if (rc <= 0)
13276c51eab1SEd Tanous         {
1328d8a5d5d8SJiaqing Zhao             messages::resourceNotFound(asyncResp->res, "ManagerAccount",
13296c51eab1SEd Tanous                                        username);
13306c51eab1SEd Tanous             return;
13316c51eab1SEd Tanous         }
13326c51eab1SEd Tanous 
13336c51eab1SEd Tanous         if (password)
13346c51eab1SEd Tanous         {
13356c51eab1SEd Tanous             int retval = pamUpdatePassword(username, *password);
13366c51eab1SEd Tanous 
13376c51eab1SEd Tanous             if (retval == PAM_USER_UNKNOWN)
13386c51eab1SEd Tanous             {
1339d8a5d5d8SJiaqing Zhao                 messages::resourceNotFound(asyncResp->res, "ManagerAccount",
13406c51eab1SEd Tanous                                            username);
13416c51eab1SEd Tanous             }
13426c51eab1SEd Tanous             else if (retval == PAM_AUTHTOK_ERR)
13436c51eab1SEd Tanous             {
13446c51eab1SEd Tanous                 // If password is invalid
13459bd80831SJason M. Bills                 messages::propertyValueFormatError(asyncResp->res, nullptr,
13469bd80831SJason M. Bills                                                    "Password");
134762598e31SEd Tanous                 BMCWEB_LOG_ERROR("pamUpdatePassword Failed");
13486c51eab1SEd Tanous             }
13496c51eab1SEd Tanous             else if (retval != PAM_SUCCESS)
13506c51eab1SEd Tanous             {
13516c51eab1SEd Tanous                 messages::internalError(asyncResp->res);
13526c51eab1SEd Tanous                 return;
13536c51eab1SEd Tanous             }
1354e7b1b62bSEd Tanous             else
1355e7b1b62bSEd Tanous             {
1356e7b1b62bSEd Tanous                 messages::success(asyncResp->res);
1357e7b1b62bSEd Tanous             }
13586c51eab1SEd Tanous         }
13596c51eab1SEd Tanous 
13606c51eab1SEd Tanous         if (enabled)
13616c51eab1SEd Tanous         {
13629ae226faSGeorge Liu             sdbusplus::asio::setProperty(
13639ae226faSGeorge Liu                 *crow::connections::systemBus,
13649ae226faSGeorge Liu                 "xyz.openbmc_project.User.Manager", dbusObjectPath,
13655a39f77aSPatrick Williams                 "xyz.openbmc_project.User.Attributes", "UserEnabled", *enabled,
13665a39f77aSPatrick Williams                 [asyncResp](const boost::system::error_code& ec) {
13676c51eab1SEd Tanous                 if (ec)
13686c51eab1SEd Tanous                 {
136962598e31SEd Tanous                     BMCWEB_LOG_ERROR("D-Bus responses error: {}", ec);
13706c51eab1SEd Tanous                     messages::internalError(asyncResp->res);
13716c51eab1SEd Tanous                     return;
13726c51eab1SEd Tanous                 }
13736c51eab1SEd Tanous                 messages::success(asyncResp->res);
13749ae226faSGeorge Liu             });
13756c51eab1SEd Tanous         }
13766c51eab1SEd Tanous 
13776c51eab1SEd Tanous         if (roleId)
13786c51eab1SEd Tanous         {
13796c51eab1SEd Tanous             std::string priv = getPrivilegeFromRoleId(*roleId);
13806c51eab1SEd Tanous             if (priv.empty())
13816c51eab1SEd Tanous             {
1382e2616cc5SEd Tanous                 messages::propertyValueNotInList(asyncResp->res, true,
1383e2616cc5SEd Tanous                                                  "Locked");
13846c51eab1SEd Tanous                 return;
13856c51eab1SEd Tanous             }
13866c51eab1SEd Tanous 
13879ae226faSGeorge Liu             sdbusplus::asio::setProperty(
13889ae226faSGeorge Liu                 *crow::connections::systemBus,
13899ae226faSGeorge Liu                 "xyz.openbmc_project.User.Manager", dbusObjectPath,
13905a39f77aSPatrick Williams                 "xyz.openbmc_project.User.Attributes", "UserPrivilege", priv,
13915a39f77aSPatrick Williams                 [asyncResp](const boost::system::error_code& ec) {
13926c51eab1SEd Tanous                 if (ec)
13936c51eab1SEd Tanous                 {
139462598e31SEd Tanous                     BMCWEB_LOG_ERROR("D-Bus responses error: {}", ec);
13956c51eab1SEd Tanous                     messages::internalError(asyncResp->res);
13966c51eab1SEd Tanous                     return;
13976c51eab1SEd Tanous                 }
13986c51eab1SEd Tanous                 messages::success(asyncResp->res);
13999ae226faSGeorge Liu             });
14006c51eab1SEd Tanous         }
14016c51eab1SEd Tanous 
14026c51eab1SEd Tanous         if (locked)
14036c51eab1SEd Tanous         {
14046c51eab1SEd Tanous             // admin can unlock the account which is locked by
14056c51eab1SEd Tanous             // successive authentication failures but admin should
14066c51eab1SEd Tanous             // not be allowed to lock an account.
14076c51eab1SEd Tanous             if (*locked)
14086c51eab1SEd Tanous             {
14096c51eab1SEd Tanous                 messages::propertyValueNotInList(asyncResp->res, "true",
14106c51eab1SEd Tanous                                                  "Locked");
14116c51eab1SEd Tanous                 return;
14126c51eab1SEd Tanous             }
14136c51eab1SEd Tanous 
14149ae226faSGeorge Liu             sdbusplus::asio::setProperty(
14159ae226faSGeorge Liu                 *crow::connections::systemBus,
14169ae226faSGeorge Liu                 "xyz.openbmc_project.User.Manager", dbusObjectPath,
14179ae226faSGeorge Liu                 "xyz.openbmc_project.User.Attributes",
14189ae226faSGeorge Liu                 "UserLockedForFailedAttempt", *locked,
14195e7e2dc5SEd Tanous                 [asyncResp](const boost::system::error_code& ec) {
14206c51eab1SEd Tanous                 if (ec)
14216c51eab1SEd Tanous                 {
142262598e31SEd Tanous                     BMCWEB_LOG_ERROR("D-Bus responses error: {}", ec);
14236c51eab1SEd Tanous                     messages::internalError(asyncResp->res);
14246c51eab1SEd Tanous                     return;
14256c51eab1SEd Tanous                 }
14266c51eab1SEd Tanous                 messages::success(asyncResp->res);
14279ae226faSGeorge Liu             });
14286c51eab1SEd Tanous         }
142958345856SAbhishek Patel 
143058345856SAbhishek Patel         if (accountTypes)
143158345856SAbhishek Patel         {
143258345856SAbhishek Patel             patchAccountTypes(*accountTypes, asyncResp, dbusObjectPath,
143358345856SAbhishek Patel                               userSelf);
143458345856SAbhishek Patel         }
14356c51eab1SEd Tanous     });
14366c51eab1SEd Tanous }
14376c51eab1SEd Tanous 
14384c7d4d33SEd Tanous inline void handleAccountServiceHead(
14394c7d4d33SEd Tanous     App& app, const crow::Request& req,
14401ef4c342SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
14416c51eab1SEd Tanous {
14423ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
144345ca1b86SEd Tanous     {
144445ca1b86SEd Tanous         return;
144545ca1b86SEd Tanous     }
14464c7d4d33SEd Tanous     asyncResp->res.addHeader(
14474c7d4d33SEd Tanous         boost::beast::http::field::link,
14484c7d4d33SEd Tanous         "</redfish/v1/JsonSchemas/AccountService/AccountService.json>; rel=describedby");
14494c7d4d33SEd Tanous }
14504c7d4d33SEd Tanous 
14514c7d4d33SEd Tanous inline void
14524c7d4d33SEd Tanous     handleAccountServiceGet(App& app, const crow::Request& req,
14534c7d4d33SEd Tanous                             const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
14544c7d4d33SEd Tanous {
1455afd369c6SJiaqing Zhao     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1456afd369c6SJiaqing Zhao     {
1457afd369c6SJiaqing Zhao         return;
1458afd369c6SJiaqing Zhao     }
14593e72c202SNinad Palsule 
14603e72c202SNinad Palsule     if (req.session == nullptr)
14613e72c202SNinad Palsule     {
14623e72c202SNinad Palsule         messages::internalError(asyncResp->res);
14633e72c202SNinad Palsule         return;
14643e72c202SNinad Palsule     }
14653e72c202SNinad Palsule 
1466afd369c6SJiaqing Zhao     asyncResp->res.addHeader(
1467afd369c6SJiaqing Zhao         boost::beast::http::field::link,
1468afd369c6SJiaqing Zhao         "</redfish/v1/JsonSchemas/AccountService/AccountService.json>; rel=describedby");
1469afd369c6SJiaqing Zhao 
147052cc112dSEd Tanous     const persistent_data::AuthConfigMethods& authMethodsConfig =
14711ef4c342SEd Tanous         persistent_data::SessionStore::getInstance().getAuthMethodsConfig();
147278158631SZbigniew Kurzynski 
14731476687dSEd Tanous     nlohmann::json& json = asyncResp->res.jsonValue;
14741476687dSEd Tanous     json["@odata.id"] = "/redfish/v1/AccountService";
14751476687dSEd Tanous     json["@odata.type"] = "#AccountService."
14761476687dSEd Tanous                           "v1_10_0.AccountService";
14771476687dSEd Tanous     json["Id"] = "AccountService";
14781476687dSEd Tanous     json["Name"] = "Account Service";
14791476687dSEd Tanous     json["Description"] = "Account Service";
14801476687dSEd Tanous     json["ServiceEnabled"] = true;
14811476687dSEd Tanous     json["MaxPasswordLength"] = 20;
14821ef4c342SEd Tanous     json["Accounts"]["@odata.id"] = "/redfish/v1/AccountService/Accounts";
14831476687dSEd Tanous     json["Roles"]["@odata.id"] = "/redfish/v1/AccountService/Roles";
14841476687dSEd Tanous     json["Oem"]["OpenBMC"]["@odata.type"] =
14855b5574acSEd Tanous         "#OpenBMCAccountService.v1_0_0.AccountService";
14861476687dSEd Tanous     json["Oem"]["OpenBMC"]["@odata.id"] =
14871476687dSEd Tanous         "/redfish/v1/AccountService#/Oem/OpenBMC";
14881476687dSEd Tanous     json["Oem"]["OpenBMC"]["AuthMethods"]["BasicAuth"] =
14891476687dSEd Tanous         authMethodsConfig.basic;
14901476687dSEd Tanous     json["Oem"]["OpenBMC"]["AuthMethods"]["SessionToken"] =
14911476687dSEd Tanous         authMethodsConfig.sessionToken;
14921ef4c342SEd Tanous     json["Oem"]["OpenBMC"]["AuthMethods"]["XToken"] = authMethodsConfig.xtoken;
14931ef4c342SEd Tanous     json["Oem"]["OpenBMC"]["AuthMethods"]["Cookie"] = authMethodsConfig.cookie;
14941ef4c342SEd Tanous     json["Oem"]["OpenBMC"]["AuthMethods"]["TLS"] = authMethodsConfig.tls;
14951476687dSEd Tanous 
14961ef4c342SEd Tanous     // /redfish/v1/AccountService/LDAP/Certificates is something only
14971ef4c342SEd Tanous     // ConfigureManager can access then only display when the user has
14981ef4c342SEd Tanous     // permissions ConfigureManager
149972048780SAbhishek Patel     Privileges effectiveUserPrivileges =
15003e72c202SNinad Palsule         redfish::getUserPrivileges(*req.session);
150172048780SAbhishek Patel 
150272048780SAbhishek Patel     if (isOperationAllowedWithPrivileges({{"ConfigureManager"}},
150372048780SAbhishek Patel                                          effectiveUserPrivileges))
150472048780SAbhishek Patel     {
15051ef4c342SEd Tanous         asyncResp->res.jsonValue["LDAP"]["Certificates"]["@odata.id"] =
15061476687dSEd Tanous             "/redfish/v1/AccountService/LDAP/Certificates";
150772048780SAbhishek Patel     }
1508d1bde9e5SKrzysztof Grobelny     sdbusplus::asio::getAllProperties(
1509d1bde9e5SKrzysztof Grobelny         *crow::connections::systemBus, "xyz.openbmc_project.User.Manager",
1510d1bde9e5SKrzysztof Grobelny         "/xyz/openbmc_project/user", "xyz.openbmc_project.User.AccountPolicy",
15115e7e2dc5SEd Tanous         [asyncResp](const boost::system::error_code& ec,
15121ef4c342SEd Tanous                     const dbus::utility::DBusPropertiesMap& propertiesList) {
15133d958bbcSAppaRao Puli         if (ec)
15143d958bbcSAppaRao Puli         {
15153d958bbcSAppaRao Puli             messages::internalError(asyncResp->res);
15163d958bbcSAppaRao Puli             return;
15173d958bbcSAppaRao Puli         }
1518d1bde9e5SKrzysztof Grobelny 
151962598e31SEd Tanous         BMCWEB_LOG_DEBUG("Got {}properties for AccountService",
152062598e31SEd Tanous                          propertiesList.size());
1521d1bde9e5SKrzysztof Grobelny 
1522d1bde9e5SKrzysztof Grobelny         const uint8_t* minPasswordLength = nullptr;
1523d1bde9e5SKrzysztof Grobelny         const uint32_t* accountUnlockTimeout = nullptr;
1524d1bde9e5SKrzysztof Grobelny         const uint16_t* maxLoginAttemptBeforeLockout = nullptr;
1525d1bde9e5SKrzysztof Grobelny 
1526d1bde9e5SKrzysztof Grobelny         const bool success = sdbusplus::unpackPropertiesNoThrow(
1527d1bde9e5SKrzysztof Grobelny             dbus_utils::UnpackErrorPrinter(), propertiesList,
1528d1bde9e5SKrzysztof Grobelny             "MinPasswordLength", minPasswordLength, "AccountUnlockTimeout",
1529d1bde9e5SKrzysztof Grobelny             accountUnlockTimeout, "MaxLoginAttemptBeforeLockout",
1530d1bde9e5SKrzysztof Grobelny             maxLoginAttemptBeforeLockout);
1531d1bde9e5SKrzysztof Grobelny 
1532d1bde9e5SKrzysztof Grobelny         if (!success)
15333d958bbcSAppaRao Puli         {
1534d1bde9e5SKrzysztof Grobelny             messages::internalError(asyncResp->res);
1535d1bde9e5SKrzysztof Grobelny             return;
15363d958bbcSAppaRao Puli         }
1537d1bde9e5SKrzysztof Grobelny 
1538d1bde9e5SKrzysztof Grobelny         if (minPasswordLength != nullptr)
15393d958bbcSAppaRao Puli         {
1540d1bde9e5SKrzysztof Grobelny             asyncResp->res.jsonValue["MinPasswordLength"] = *minPasswordLength;
15413d958bbcSAppaRao Puli         }
1542d1bde9e5SKrzysztof Grobelny 
1543d1bde9e5SKrzysztof Grobelny         if (accountUnlockTimeout != nullptr)
15443d958bbcSAppaRao Puli         {
1545d1bde9e5SKrzysztof Grobelny             asyncResp->res.jsonValue["AccountLockoutDuration"] =
1546d1bde9e5SKrzysztof Grobelny                 *accountUnlockTimeout;
1547d1bde9e5SKrzysztof Grobelny         }
1548d1bde9e5SKrzysztof Grobelny 
1549d1bde9e5SKrzysztof Grobelny         if (maxLoginAttemptBeforeLockout != nullptr)
15503d958bbcSAppaRao Puli         {
1551002d39b4SEd Tanous             asyncResp->res.jsonValue["AccountLockoutThreshold"] =
1552d1bde9e5SKrzysztof Grobelny                 *maxLoginAttemptBeforeLockout;
15533d958bbcSAppaRao Puli         }
1554d1bde9e5SKrzysztof Grobelny     });
15556973a582SRatan Gupta 
155602cad96eSEd Tanous     auto callback = [asyncResp](bool success, const LDAPConfigData& confData,
1557ab828d7cSRatan Gupta                                 const std::string& ldapType) {
1558cb13a392SEd Tanous         if (!success)
1559cb13a392SEd Tanous         {
1560cb13a392SEd Tanous             return;
1561cb13a392SEd Tanous         }
1562002d39b4SEd Tanous         parseLDAPConfigData(asyncResp->res.jsonValue, confData, ldapType);
1563ab828d7cSRatan Gupta     };
1564ab828d7cSRatan Gupta 
1565ab828d7cSRatan Gupta     getLDAPConfigData("LDAP", callback);
1566ab828d7cSRatan Gupta     getLDAPConfigData("ActiveDirectory", callback);
15671ef4c342SEd Tanous }
15686973a582SRatan Gupta 
15691ef4c342SEd Tanous inline void handleAccountServicePatch(
15701ef4c342SEd Tanous     App& app, const crow::Request& req,
15711ef4c342SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
15721ef4c342SEd Tanous {
15733ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
157445ca1b86SEd Tanous     {
157545ca1b86SEd Tanous         return;
157645ca1b86SEd Tanous     }
1577f5ffd806SEd Tanous     std::optional<uint32_t> unlockTimeout;
1578f5ffd806SEd Tanous     std::optional<uint16_t> lockoutThreshold;
1579ef73ad0dSPaul Fertser     std::optional<uint8_t> minPasswordLength;
1580f5ffd806SEd Tanous     std::optional<uint16_t> maxPasswordLength;
1581f5ffd806SEd Tanous     std::optional<nlohmann::json> ldapObject;
1582f5ffd806SEd Tanous     std::optional<nlohmann::json> activeDirectoryObject;
1583f5ffd806SEd Tanous     std::optional<nlohmann::json> oemObject;
1584f5ffd806SEd Tanous 
158515ed6780SWilly Tu     if (!json_util::readJsonPatch(
15861ef4c342SEd Tanous             req, asyncResp->res, "AccountLockoutDuration", unlockTimeout,
15871ef4c342SEd Tanous             "AccountLockoutThreshold", lockoutThreshold, "MaxPasswordLength",
15881ef4c342SEd Tanous             maxPasswordLength, "MinPasswordLength", minPasswordLength, "LDAP",
15891ef4c342SEd Tanous             ldapObject, "ActiveDirectory", activeDirectoryObject, "Oem",
1590f5ffd806SEd Tanous             oemObject))
1591f5ffd806SEd Tanous     {
1592f5ffd806SEd Tanous         return;
1593f5ffd806SEd Tanous     }
1594f5ffd806SEd Tanous 
1595f5ffd806SEd Tanous     if (minPasswordLength)
1596f5ffd806SEd Tanous     {
15979ae226faSGeorge Liu         sdbusplus::asio::setProperty(
15989ae226faSGeorge Liu             *crow::connections::systemBus, "xyz.openbmc_project.User.Manager",
15999ae226faSGeorge Liu             "/xyz/openbmc_project/user",
16009ae226faSGeorge Liu             "xyz.openbmc_project.User.AccountPolicy", "MinPasswordLength",
16019ae226faSGeorge Liu             *minPasswordLength,
16025e7e2dc5SEd Tanous             [asyncResp](const boost::system::error_code& ec) {
1603ef73ad0dSPaul Fertser             if (ec)
1604ef73ad0dSPaul Fertser             {
1605ef73ad0dSPaul Fertser                 messages::internalError(asyncResp->res);
1606ef73ad0dSPaul Fertser                 return;
1607ef73ad0dSPaul Fertser             }
1608ef73ad0dSPaul Fertser             messages::success(asyncResp->res);
16099ae226faSGeorge Liu         });
1610f5ffd806SEd Tanous     }
1611f5ffd806SEd Tanous 
1612f5ffd806SEd Tanous     if (maxPasswordLength)
1613f5ffd806SEd Tanous     {
16141ef4c342SEd Tanous         messages::propertyNotWritable(asyncResp->res, "MaxPasswordLength");
1615f5ffd806SEd Tanous     }
1616f5ffd806SEd Tanous 
1617f5ffd806SEd Tanous     if (ldapObject)
1618f5ffd806SEd Tanous     {
1619f5ffd806SEd Tanous         handleLDAPPatch(*ldapObject, asyncResp, "LDAP");
1620f5ffd806SEd Tanous     }
1621f5ffd806SEd Tanous 
1622f5ffd806SEd Tanous     if (std::optional<nlohmann::json> oemOpenBMCObject;
16231ef4c342SEd Tanous         oemObject && json_util::readJson(*oemObject, asyncResp->res, "OpenBMC",
1624f5ffd806SEd Tanous                                          oemOpenBMCObject))
1625f5ffd806SEd Tanous     {
1626f5ffd806SEd Tanous         if (std::optional<nlohmann::json> authMethodsObject;
1627f5ffd806SEd Tanous             oemOpenBMCObject &&
1628f5ffd806SEd Tanous             json_util::readJson(*oemOpenBMCObject, asyncResp->res,
1629f5ffd806SEd Tanous                                 "AuthMethods", authMethodsObject))
1630f5ffd806SEd Tanous         {
1631f5ffd806SEd Tanous             if (authMethodsObject)
1632f5ffd806SEd Tanous             {
16331ef4c342SEd Tanous                 handleAuthMethodsPatch(*authMethodsObject, asyncResp);
1634f5ffd806SEd Tanous             }
1635f5ffd806SEd Tanous         }
1636f5ffd806SEd Tanous     }
1637f5ffd806SEd Tanous 
1638f5ffd806SEd Tanous     if (activeDirectoryObject)
1639f5ffd806SEd Tanous     {
16401ef4c342SEd Tanous         handleLDAPPatch(*activeDirectoryObject, asyncResp, "ActiveDirectory");
1641f5ffd806SEd Tanous     }
1642f5ffd806SEd Tanous 
1643f5ffd806SEd Tanous     if (unlockTimeout)
1644f5ffd806SEd Tanous     {
16459ae226faSGeorge Liu         sdbusplus::asio::setProperty(
16469ae226faSGeorge Liu             *crow::connections::systemBus, "xyz.openbmc_project.User.Manager",
16479ae226faSGeorge Liu             "/xyz/openbmc_project/user",
16489ae226faSGeorge Liu             "xyz.openbmc_project.User.AccountPolicy", "AccountUnlockTimeout",
16499ae226faSGeorge Liu             *unlockTimeout, [asyncResp](const boost::system::error_code& ec) {
1650f5ffd806SEd Tanous             if (ec)
1651f5ffd806SEd Tanous             {
1652f5ffd806SEd Tanous                 messages::internalError(asyncResp->res);
1653f5ffd806SEd Tanous                 return;
1654f5ffd806SEd Tanous             }
1655f5ffd806SEd Tanous             messages::success(asyncResp->res);
16569ae226faSGeorge Liu         });
1657f5ffd806SEd Tanous     }
1658f5ffd806SEd Tanous     if (lockoutThreshold)
1659f5ffd806SEd Tanous     {
16609ae226faSGeorge Liu         sdbusplus::asio::setProperty(
16619ae226faSGeorge Liu             *crow::connections::systemBus, "xyz.openbmc_project.User.Manager",
16629ae226faSGeorge Liu             "/xyz/openbmc_project/user",
16639ae226faSGeorge Liu             "xyz.openbmc_project.User.AccountPolicy",
16649ae226faSGeorge Liu             "MaxLoginAttemptBeforeLockout", *lockoutThreshold,
16655e7e2dc5SEd Tanous             [asyncResp](const boost::system::error_code& ec) {
1666f5ffd806SEd Tanous             if (ec)
1667f5ffd806SEd Tanous             {
1668f5ffd806SEd Tanous                 messages::internalError(asyncResp->res);
1669f5ffd806SEd Tanous                 return;
1670f5ffd806SEd Tanous             }
1671f5ffd806SEd Tanous             messages::success(asyncResp->res);
16729ae226faSGeorge Liu         });
1673f5ffd806SEd Tanous     }
16741ef4c342SEd Tanous }
1675f5ffd806SEd Tanous 
16764c7d4d33SEd Tanous inline void handleAccountCollectionHead(
16771ef4c342SEd Tanous     App& app, const crow::Request& req,
16781ef4c342SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
16791ef4c342SEd Tanous {
16803ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
168145ca1b86SEd Tanous     {
168245ca1b86SEd Tanous         return;
168345ca1b86SEd Tanous     }
16844c7d4d33SEd Tanous     asyncResp->res.addHeader(
16854c7d4d33SEd Tanous         boost::beast::http::field::link,
16864c7d4d33SEd Tanous         "</redfish/v1/JsonSchemas/ManagerAccountCollection.json>; rel=describedby");
16874c7d4d33SEd Tanous }
16884c7d4d33SEd Tanous 
16894c7d4d33SEd Tanous inline void handleAccountCollectionGet(
16904c7d4d33SEd Tanous     App& app, const crow::Request& req,
16914c7d4d33SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
16924c7d4d33SEd Tanous {
1693afd369c6SJiaqing Zhao     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1694afd369c6SJiaqing Zhao     {
1695afd369c6SJiaqing Zhao         return;
1696afd369c6SJiaqing Zhao     }
16973e72c202SNinad Palsule 
16983e72c202SNinad Palsule     if (req.session == nullptr)
16993e72c202SNinad Palsule     {
17003e72c202SNinad Palsule         messages::internalError(asyncResp->res);
17013e72c202SNinad Palsule         return;
17023e72c202SNinad Palsule     }
17033e72c202SNinad Palsule 
1704afd369c6SJiaqing Zhao     asyncResp->res.addHeader(
1705afd369c6SJiaqing Zhao         boost::beast::http::field::link,
1706afd369c6SJiaqing Zhao         "</redfish/v1/JsonSchemas/ManagerAccountCollection.json>; rel=describedby");
17071476687dSEd Tanous 
17081476687dSEd Tanous     asyncResp->res.jsonValue["@odata.id"] =
17091476687dSEd Tanous         "/redfish/v1/AccountService/Accounts";
17101ef4c342SEd Tanous     asyncResp->res.jsonValue["@odata.type"] = "#ManagerAccountCollection."
17111476687dSEd Tanous                                               "ManagerAccountCollection";
17121476687dSEd Tanous     asyncResp->res.jsonValue["Name"] = "Accounts Collection";
17131476687dSEd Tanous     asyncResp->res.jsonValue["Description"] = "BMC User Accounts";
17140f74e643SEd Tanous 
17156c51eab1SEd Tanous     Privileges effectiveUserPrivileges =
17163e72c202SNinad Palsule         redfish::getUserPrivileges(*req.session);
17176c51eab1SEd Tanous 
1718f5e29f33SJunLin Chen     std::string thisUser;
1719f5e29f33SJunLin Chen     if (req.session)
1720f5e29f33SJunLin Chen     {
1721f5e29f33SJunLin Chen         thisUser = req.session->username;
1722f5e29f33SJunLin Chen     }
17235eb468daSGeorge Liu     sdbusplus::message::object_path path("/xyz/openbmc_project/user");
17245eb468daSGeorge Liu     dbus::utility::getManagedObjects(
17255eb468daSGeorge Liu         "xyz.openbmc_project.User.Manager", path,
1726cef1ddfbSEd Tanous         [asyncResp, thisUser, effectiveUserPrivileges](
17275e7e2dc5SEd Tanous             const boost::system::error_code& ec,
1728711ac7a9SEd Tanous             const dbus::utility::ManagedObjectType& users) {
1729b9b2e0b2SEd Tanous         if (ec)
1730b9b2e0b2SEd Tanous         {
1731f12894f8SJason M. Bills             messages::internalError(asyncResp->res);
1732b9b2e0b2SEd Tanous             return;
1733b9b2e0b2SEd Tanous         }
1734b9b2e0b2SEd Tanous 
1735cef1ddfbSEd Tanous         bool userCanSeeAllAccounts =
1736002d39b4SEd Tanous             effectiveUserPrivileges.isSupersetOf({"ConfigureUsers"});
1737cef1ddfbSEd Tanous 
1738cef1ddfbSEd Tanous         bool userCanSeeSelf =
1739002d39b4SEd Tanous             effectiveUserPrivileges.isSupersetOf({"ConfigureSelf"});
1740cef1ddfbSEd Tanous 
1741002d39b4SEd Tanous         nlohmann::json& memberArray = asyncResp->res.jsonValue["Members"];
1742b9b2e0b2SEd Tanous         memberArray = nlohmann::json::array();
1743b9b2e0b2SEd Tanous 
17449eb808c1SEd Tanous         for (const auto& userpath : users)
1745b9b2e0b2SEd Tanous         {
17462dfd18efSEd Tanous             std::string user = userpath.first.filename();
17472dfd18efSEd Tanous             if (user.empty())
1748b9b2e0b2SEd Tanous             {
17492dfd18efSEd Tanous                 messages::internalError(asyncResp->res);
175062598e31SEd Tanous                 BMCWEB_LOG_ERROR("Invalid firmware ID");
17512dfd18efSEd Tanous 
17522dfd18efSEd Tanous                 return;
1753b9b2e0b2SEd Tanous             }
1754f365910cSGunnar Mills 
1755f365910cSGunnar Mills             // As clarified by Redfish here:
1756f365910cSGunnar Mills             // https://redfishforum.com/thread/281/manageraccountcollection-change-allows-account-enumeration
17576c51eab1SEd Tanous             // Users without ConfigureUsers, only see their own
17586c51eab1SEd Tanous             // account. Users with ConfigureUsers, see all
17596c51eab1SEd Tanous             // accounts.
17601ef4c342SEd Tanous             if (userCanSeeAllAccounts || (thisUser == user && userCanSeeSelf))
1761f365910cSGunnar Mills             {
17621476687dSEd Tanous                 nlohmann::json::object_t member;
17633b32780dSEd Tanous                 member["@odata.id"] = boost::urls::format(
17643b32780dSEd Tanous                     "/redfish/v1/AccountService/Accounts/{}", user);
1765b2ba3072SPatrick Williams                 memberArray.emplace_back(std::move(member));
1766b9b2e0b2SEd Tanous             }
1767f365910cSGunnar Mills         }
17681ef4c342SEd Tanous         asyncResp->res.jsonValue["Members@odata.count"] = memberArray.size();
17695eb468daSGeorge Liu     });
17701ef4c342SEd Tanous }
17716c51eab1SEd Tanous 
177297e90da3SNinad Palsule inline void processAfterCreateUser(
177397e90da3SNinad Palsule     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
177497e90da3SNinad Palsule     const std::string& username, const std::string& password,
177597e90da3SNinad Palsule     const boost::system::error_code& ec, sdbusplus::message_t& m)
177697e90da3SNinad Palsule {
177797e90da3SNinad Palsule     if (ec)
177897e90da3SNinad Palsule     {
177997e90da3SNinad Palsule         userErrorMessageHandler(m.get_error(), asyncResp, username, "");
178097e90da3SNinad Palsule         return;
178197e90da3SNinad Palsule     }
178297e90da3SNinad Palsule 
178397e90da3SNinad Palsule     if (pamUpdatePassword(username, password) != PAM_SUCCESS)
178497e90da3SNinad Palsule     {
178597e90da3SNinad Palsule         // At this point we have a user that's been
178697e90da3SNinad Palsule         // created, but the password set
178797e90da3SNinad Palsule         // failed.Something is wrong, so delete the user
178897e90da3SNinad Palsule         // that we've already created
178997e90da3SNinad Palsule         sdbusplus::message::object_path tempObjPath(rootUserDbusPath);
179097e90da3SNinad Palsule         tempObjPath /= username;
179197e90da3SNinad Palsule         const std::string userPath(tempObjPath);
179297e90da3SNinad Palsule 
179397e90da3SNinad Palsule         crow::connections::systemBus->async_method_call(
179497e90da3SNinad Palsule             [asyncResp, password](const boost::system::error_code& ec3) {
179597e90da3SNinad Palsule             if (ec3)
179697e90da3SNinad Palsule             {
179797e90da3SNinad Palsule                 messages::internalError(asyncResp->res);
179897e90da3SNinad Palsule                 return;
179997e90da3SNinad Palsule             }
180097e90da3SNinad Palsule 
180197e90da3SNinad Palsule             // If password is invalid
18029bd80831SJason M. Bills             messages::propertyValueFormatError(asyncResp->res, nullptr,
180397e90da3SNinad Palsule                                                "Password");
180497e90da3SNinad Palsule         },
180597e90da3SNinad Palsule             "xyz.openbmc_project.User.Manager", userPath,
180697e90da3SNinad Palsule             "xyz.openbmc_project.Object.Delete", "Delete");
180797e90da3SNinad Palsule 
180862598e31SEd Tanous         BMCWEB_LOG_ERROR("pamUpdatePassword Failed");
180997e90da3SNinad Palsule         return;
181097e90da3SNinad Palsule     }
181197e90da3SNinad Palsule 
181297e90da3SNinad Palsule     messages::created(asyncResp->res);
181397e90da3SNinad Palsule     asyncResp->res.addHeader("Location",
181497e90da3SNinad Palsule                              "/redfish/v1/AccountService/Accounts/" + username);
181597e90da3SNinad Palsule }
181697e90da3SNinad Palsule 
181797e90da3SNinad Palsule inline void processAfterGetAllGroups(
181897e90da3SNinad Palsule     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
181997e90da3SNinad Palsule     const std::string& username, const std::string& password,
1820e01d0c36SEd Tanous     const std::string& roleId, bool enabled,
18219ba73934SNinad Palsule     std::optional<std::vector<std::string>> accountTypes,
182297e90da3SNinad Palsule     const std::vector<std::string>& allGroupsList)
182397e90da3SNinad Palsule {
18243e72c202SNinad Palsule     std::vector<std::string> userGroups;
18259ba73934SNinad Palsule     std::vector<std::string> accountTypeUserGroups;
18269ba73934SNinad Palsule 
18279ba73934SNinad Palsule     // If user specified account types then convert them to unix user groups
18289ba73934SNinad Palsule     if (accountTypes)
18299ba73934SNinad Palsule     {
18309ba73934SNinad Palsule         if (!getUserGroupFromAccountType(asyncResp->res, *accountTypes,
18319ba73934SNinad Palsule                                          accountTypeUserGroups))
18329ba73934SNinad Palsule         {
18339ba73934SNinad Palsule             // Problem in mapping Account Types to User Groups, Error already
18349ba73934SNinad Palsule             // logged.
18359ba73934SNinad Palsule             return;
18369ba73934SNinad Palsule         }
18379ba73934SNinad Palsule     }
18389ba73934SNinad Palsule 
18393e72c202SNinad Palsule     for (const auto& grp : allGroupsList)
18403e72c202SNinad Palsule     {
18419ba73934SNinad Palsule         // If user specified the account type then only accept groups which are
18429ba73934SNinad Palsule         // in the account types group list.
18439ba73934SNinad Palsule         if (!accountTypeUserGroups.empty())
18449ba73934SNinad Palsule         {
18459ba73934SNinad Palsule             bool found = false;
18469ba73934SNinad Palsule             for (const auto& grp1 : accountTypeUserGroups)
18479ba73934SNinad Palsule             {
18489ba73934SNinad Palsule                 if (grp == grp1)
18499ba73934SNinad Palsule                 {
18509ba73934SNinad Palsule                     found = true;
18519ba73934SNinad Palsule                     break;
18529ba73934SNinad Palsule                 }
18539ba73934SNinad Palsule             }
18549ba73934SNinad Palsule             if (!found)
18559ba73934SNinad Palsule             {
18569ba73934SNinad Palsule                 continue;
18579ba73934SNinad Palsule             }
18589ba73934SNinad Palsule         }
18599ba73934SNinad Palsule 
18603e72c202SNinad Palsule         // Console access is provided to the user who is a member of
18613e72c202SNinad Palsule         // hostconsole group and has a administrator role. So, set
18623e72c202SNinad Palsule         // hostconsole group only for the administrator.
18639ba73934SNinad Palsule         if ((grp == "hostconsole") && (roleId != "priv-admin"))
18643e72c202SNinad Palsule         {
18659ba73934SNinad Palsule             if (!accountTypeUserGroups.empty())
18669ba73934SNinad Palsule             {
186762598e31SEd Tanous                 BMCWEB_LOG_ERROR(
186862598e31SEd Tanous                     "Only administrator can get HostConsole access");
18699ba73934SNinad Palsule                 asyncResp->res.result(boost::beast::http::status::bad_request);
18709ba73934SNinad Palsule                 return;
18719ba73934SNinad Palsule             }
18729ba73934SNinad Palsule             continue;
18739ba73934SNinad Palsule         }
18743e72c202SNinad Palsule         userGroups.emplace_back(grp);
18753e72c202SNinad Palsule     }
18769ba73934SNinad Palsule 
18779ba73934SNinad Palsule     // Make sure user specified groups are valid. This is internal error because
18789ba73934SNinad Palsule     // it some inconsistencies between user manager and bmcweb.
18799ba73934SNinad Palsule     if (!accountTypeUserGroups.empty() &&
18809ba73934SNinad Palsule         accountTypeUserGroups.size() != userGroups.size())
18819ba73934SNinad Palsule     {
18829ba73934SNinad Palsule         messages::internalError(asyncResp->res);
18839ba73934SNinad Palsule         return;
18843e72c202SNinad Palsule     }
188597e90da3SNinad Palsule     crow::connections::systemBus->async_method_call(
188697e90da3SNinad Palsule         [asyncResp, username, password](const boost::system::error_code& ec2,
188797e90da3SNinad Palsule                                         sdbusplus::message_t& m) {
188897e90da3SNinad Palsule         processAfterCreateUser(asyncResp, username, password, ec2, m);
188997e90da3SNinad Palsule     },
189097e90da3SNinad Palsule         "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
18913e72c202SNinad Palsule         "xyz.openbmc_project.User.Manager", "CreateUser", username, userGroups,
1892e01d0c36SEd Tanous         roleId, enabled);
189397e90da3SNinad Palsule }
189497e90da3SNinad Palsule 
18951ef4c342SEd Tanous inline void handleAccountCollectionPost(
18961ef4c342SEd Tanous     App& app, const crow::Request& req,
18971ef4c342SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
18981ef4c342SEd Tanous {
18993ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
190045ca1b86SEd Tanous     {
190145ca1b86SEd Tanous         return;
190245ca1b86SEd Tanous     }
19039712f8acSEd Tanous     std::string username;
19049712f8acSEd Tanous     std::string password;
1905e01d0c36SEd Tanous     std::optional<std::string> roleIdJson;
1906e01d0c36SEd Tanous     std::optional<bool> enabledJson;
19079ba73934SNinad Palsule     std::optional<std::vector<std::string>> accountTypes;
1908e01d0c36SEd Tanous     if (!json_util::readJsonPatch(req, asyncResp->res, "UserName", username,
1909e01d0c36SEd Tanous                                   "Password", password, "RoleId", roleIdJson,
1910e01d0c36SEd Tanous                                   "Enabled", enabledJson, "AccountTypes",
1911e01d0c36SEd Tanous                                   accountTypes))
191204ae99ecSEd Tanous     {
191304ae99ecSEd Tanous         return;
191404ae99ecSEd Tanous     }
191504ae99ecSEd Tanous 
1916e01d0c36SEd Tanous     std::string roleId = roleIdJson.value_or("User");
1917e01d0c36SEd Tanous     std::string priv = getPrivilegeFromRoleId(roleId);
191884e12cb7SAppaRao Puli     if (priv.empty())
191904ae99ecSEd Tanous     {
1920e01d0c36SEd Tanous         messages::propertyValueNotInList(asyncResp->res, roleId, "RoleId");
192104ae99ecSEd Tanous         return;
192204ae99ecSEd Tanous     }
19239712f8acSEd Tanous     roleId = priv;
192404ae99ecSEd Tanous 
1925e01d0c36SEd Tanous     bool enabled = enabledJson.value_or(true);
1926e01d0c36SEd Tanous 
1927599c71d8SAyushi Smriti     // Reading AllGroups property
19281e1e598dSJonathan Doman     sdbusplus::asio::getProperty<std::vector<std::string>>(
19291ef4c342SEd Tanous         *crow::connections::systemBus, "xyz.openbmc_project.User.Manager",
19301ef4c342SEd Tanous         "/xyz/openbmc_project/user", "xyz.openbmc_project.User.Manager",
19311ef4c342SEd Tanous         "AllGroups",
19329ba73934SNinad Palsule         [asyncResp, username, password{std::move(password)}, roleId, enabled,
19339ba73934SNinad Palsule          accountTypes](const boost::system::error_code& ec,
19341e1e598dSJonathan Doman                        const std::vector<std::string>& allGroupsList) {
1935599c71d8SAyushi Smriti         if (ec)
1936599c71d8SAyushi Smriti         {
193762598e31SEd Tanous             BMCWEB_LOG_DEBUG("ERROR with async_method_call");
1938599c71d8SAyushi Smriti             messages::internalError(asyncResp->res);
1939599c71d8SAyushi Smriti             return;
1940599c71d8SAyushi Smriti         }
1941599c71d8SAyushi Smriti 
19421e1e598dSJonathan Doman         if (allGroupsList.empty())
1943599c71d8SAyushi Smriti         {
1944599c71d8SAyushi Smriti             messages::internalError(asyncResp->res);
1945599c71d8SAyushi Smriti             return;
1946599c71d8SAyushi Smriti         }
1947599c71d8SAyushi Smriti 
194897e90da3SNinad Palsule         processAfterGetAllGroups(asyncResp, username, password, roleId, enabled,
19499ba73934SNinad Palsule                                  accountTypes, allGroupsList);
19501e1e598dSJonathan Doman     });
19511ef4c342SEd Tanous }
1952b9b2e0b2SEd Tanous 
19531ef4c342SEd Tanous inline void
19544c7d4d33SEd Tanous     handleAccountHead(App& app, const crow::Request& req,
19556c51eab1SEd Tanous                       const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
19564c7d4d33SEd Tanous                       const std::string& /*accountName*/)
19571ef4c342SEd Tanous {
19583ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
195945ca1b86SEd Tanous     {
196045ca1b86SEd Tanous         return;
196145ca1b86SEd Tanous     }
19624c7d4d33SEd Tanous     asyncResp->res.addHeader(
19634c7d4d33SEd Tanous         boost::beast::http::field::link,
19644c7d4d33SEd Tanous         "</redfish/v1/JsonSchemas/ManagerAccount/ManagerAccount.json>; rel=describedby");
19654c7d4d33SEd Tanous }
1966afd369c6SJiaqing Zhao 
19674c7d4d33SEd Tanous inline void
19684c7d4d33SEd Tanous     handleAccountGet(App& app, const crow::Request& req,
19694c7d4d33SEd Tanous                      const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
19704c7d4d33SEd Tanous                      const std::string& accountName)
19714c7d4d33SEd Tanous {
1972afd369c6SJiaqing Zhao     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1973afd369c6SJiaqing Zhao     {
1974afd369c6SJiaqing Zhao         return;
1975afd369c6SJiaqing Zhao     }
1976afd369c6SJiaqing Zhao     asyncResp->res.addHeader(
1977afd369c6SJiaqing Zhao         boost::beast::http::field::link,
1978afd369c6SJiaqing Zhao         "</redfish/v1/JsonSchemas/ManagerAccount/ManagerAccount.json>; rel=describedby");
1979afd369c6SJiaqing Zhao 
19801ef4c342SEd Tanous #ifdef BMCWEB_INSECURE_DISABLE_AUTHENTICATION
1981031514fbSJunLin Chen     // If authentication is disabled, there are no user accounts
1982d8a5d5d8SJiaqing Zhao     messages::resourceNotFound(asyncResp->res, "ManagerAccount", accountName);
1983031514fbSJunLin Chen     return;
19841ef4c342SEd Tanous #endif // BMCWEB_INSECURE_DISABLE_AUTHENTICATION
1985afd369c6SJiaqing Zhao 
1986031514fbSJunLin Chen     if (req.session == nullptr)
1987031514fbSJunLin Chen     {
1988031514fbSJunLin Chen         messages::internalError(asyncResp->res);
1989031514fbSJunLin Chen         return;
1990031514fbSJunLin Chen     }
19916c51eab1SEd Tanous     if (req.session->username != accountName)
1992b9b2e0b2SEd Tanous     {
19936c51eab1SEd Tanous         // At this point we've determined that the user is trying to
19941ef4c342SEd Tanous         // modify a user that isn't them.  We need to verify that they
19951ef4c342SEd Tanous         // have permissions to modify other users, so re-run the auth
19961ef4c342SEd Tanous         // check with the same permissions, minus ConfigureSelf.
19976c51eab1SEd Tanous         Privileges effectiveUserPrivileges =
19983e72c202SNinad Palsule             redfish::getUserPrivileges(*req.session);
19991ef4c342SEd Tanous         Privileges requiredPermissionsToChangeNonSelf = {"ConfigureUsers",
20001ef4c342SEd Tanous                                                          "ConfigureManager"};
20016c51eab1SEd Tanous         if (!effectiveUserPrivileges.isSupersetOf(
20026c51eab1SEd Tanous                 requiredPermissionsToChangeNonSelf))
2003900f9497SJoseph Reynolds         {
200462598e31SEd Tanous             BMCWEB_LOG_DEBUG("GET Account denied access");
2005900f9497SJoseph Reynolds             messages::insufficientPrivilege(asyncResp->res);
2006900f9497SJoseph Reynolds             return;
2007900f9497SJoseph Reynolds         }
2008900f9497SJoseph Reynolds     }
2009900f9497SJoseph Reynolds 
20105eb468daSGeorge Liu     sdbusplus::message::object_path path("/xyz/openbmc_project/user");
20115eb468daSGeorge Liu     dbus::utility::getManagedObjects(
20125eb468daSGeorge Liu         "xyz.openbmc_project.User.Manager", path,
20131ef4c342SEd Tanous         [asyncResp,
20145e7e2dc5SEd Tanous          accountName](const boost::system::error_code& ec,
2015711ac7a9SEd Tanous                       const dbus::utility::ManagedObjectType& users) {
2016b9b2e0b2SEd Tanous         if (ec)
2017b9b2e0b2SEd Tanous         {
2018f12894f8SJason M. Bills             messages::internalError(asyncResp->res);
2019b9b2e0b2SEd Tanous             return;
2020b9b2e0b2SEd Tanous         }
20213544d2a7SEd Tanous         const auto userIt = std::ranges::find_if(
202280f79a40SMichael Shen             users,
202380f79a40SMichael Shen             [accountName](
2024b477fd44SP Dheeraj Srujan Kumar                 const std::pair<sdbusplus::message::object_path,
202580f79a40SMichael Shen                                 dbus::utility::DBusInterfacesMap>& user) {
202655f79e6fSEd Tanous             return accountName == user.first.filename();
2027b477fd44SP Dheeraj Srujan Kumar         });
2028b9b2e0b2SEd Tanous 
202984e12cb7SAppaRao Puli         if (userIt == users.end())
2030b9b2e0b2SEd Tanous         {
2031002d39b4SEd Tanous             messages::resourceNotFound(asyncResp->res, "ManagerAccount",
2032002d39b4SEd Tanous                                        accountName);
203384e12cb7SAppaRao Puli             return;
203484e12cb7SAppaRao Puli         }
20354e68c45bSAyushi Smriti 
20361476687dSEd Tanous         asyncResp->res.jsonValue["@odata.type"] =
203758345856SAbhishek Patel             "#ManagerAccount.v1_7_0.ManagerAccount";
20381476687dSEd Tanous         asyncResp->res.jsonValue["Name"] = "User Account";
20391476687dSEd Tanous         asyncResp->res.jsonValue["Description"] = "User Account";
20401476687dSEd Tanous         asyncResp->res.jsonValue["Password"] = nullptr;
204158345856SAbhishek Patel         asyncResp->res.jsonValue["StrictAccountTypes"] = true;
20424e68c45bSAyushi Smriti 
204384e12cb7SAppaRao Puli         for (const auto& interface : userIt->second)
204465b0dc32SEd Tanous         {
2045002d39b4SEd Tanous             if (interface.first == "xyz.openbmc_project.User.Attributes")
204665b0dc32SEd Tanous             {
204765b0dc32SEd Tanous                 for (const auto& property : interface.second)
204865b0dc32SEd Tanous                 {
204965b0dc32SEd Tanous                     if (property.first == "UserEnabled")
205065b0dc32SEd Tanous                     {
205165b0dc32SEd Tanous                         const bool* userEnabled =
2052abf2add6SEd Tanous                             std::get_if<bool>(&property.second);
205365b0dc32SEd Tanous                         if (userEnabled == nullptr)
205465b0dc32SEd Tanous                         {
205562598e31SEd Tanous                             BMCWEB_LOG_ERROR("UserEnabled wasn't a bool");
205684e12cb7SAppaRao Puli                             messages::internalError(asyncResp->res);
205784e12cb7SAppaRao Puli                             return;
205865b0dc32SEd Tanous                         }
2059002d39b4SEd Tanous                         asyncResp->res.jsonValue["Enabled"] = *userEnabled;
206065b0dc32SEd Tanous                     }
2061002d39b4SEd Tanous                     else if (property.first == "UserLockedForFailedAttempt")
206265b0dc32SEd Tanous                     {
206365b0dc32SEd Tanous                         const bool* userLocked =
2064abf2add6SEd Tanous                             std::get_if<bool>(&property.second);
206565b0dc32SEd Tanous                         if (userLocked == nullptr)
206665b0dc32SEd Tanous                         {
206762598e31SEd Tanous                             BMCWEB_LOG_ERROR("UserLockedForF"
206884e12cb7SAppaRao Puli                                              "ailedAttempt "
206962598e31SEd Tanous                                              "wasn't a bool");
207084e12cb7SAppaRao Puli                             messages::internalError(asyncResp->res);
207184e12cb7SAppaRao Puli                             return;
207265b0dc32SEd Tanous                         }
2073002d39b4SEd Tanous                         asyncResp->res.jsonValue["Locked"] = *userLocked;
2074002d39b4SEd Tanous                         asyncResp->res
2075002d39b4SEd Tanous                             .jsonValue["Locked@Redfish.AllowableValues"] = {
20763bf4e632SJoseph Reynolds                             "false"}; // can only unlock accounts
207765b0dc32SEd Tanous                     }
207884e12cb7SAppaRao Puli                     else if (property.first == "UserPrivilege")
207984e12cb7SAppaRao Puli                     {
208054fc587aSNagaraju Goruganti                         const std::string* userPrivPtr =
2081002d39b4SEd Tanous                             std::get_if<std::string>(&property.second);
208254fc587aSNagaraju Goruganti                         if (userPrivPtr == nullptr)
208384e12cb7SAppaRao Puli                         {
208462598e31SEd Tanous                             BMCWEB_LOG_ERROR("UserPrivilege wasn't a "
208562598e31SEd Tanous                                              "string");
208684e12cb7SAppaRao Puli                             messages::internalError(asyncResp->res);
208784e12cb7SAppaRao Puli                             return;
208884e12cb7SAppaRao Puli                         }
20891ef4c342SEd Tanous                         std::string role = getRoleIdFromPrivilege(*userPrivPtr);
209054fc587aSNagaraju Goruganti                         if (role.empty())
209184e12cb7SAppaRao Puli                         {
209262598e31SEd Tanous                             BMCWEB_LOG_ERROR("Invalid user role");
209384e12cb7SAppaRao Puli                             messages::internalError(asyncResp->res);
209484e12cb7SAppaRao Puli                             return;
209584e12cb7SAppaRao Puli                         }
209654fc587aSNagaraju Goruganti                         asyncResp->res.jsonValue["RoleId"] = role;
209784e12cb7SAppaRao Puli 
20981476687dSEd Tanous                         nlohmann::json& roleEntry =
2099002d39b4SEd Tanous                             asyncResp->res.jsonValue["Links"]["Role"];
21003b32780dSEd Tanous                         roleEntry["@odata.id"] = boost::urls::format(
21013b32780dSEd Tanous                             "/redfish/v1/AccountService/Roles/{}", role);
210284e12cb7SAppaRao Puli                     }
2103002d39b4SEd Tanous                     else if (property.first == "UserPasswordExpired")
21043bf4e632SJoseph Reynolds                     {
21053bf4e632SJoseph Reynolds                         const bool* userPasswordExpired =
21063bf4e632SJoseph Reynolds                             std::get_if<bool>(&property.second);
21073bf4e632SJoseph Reynolds                         if (userPasswordExpired == nullptr)
21083bf4e632SJoseph Reynolds                         {
210962598e31SEd Tanous                             BMCWEB_LOG_ERROR(
211062598e31SEd Tanous                                 "UserPasswordExpired wasn't a bool");
21113bf4e632SJoseph Reynolds                             messages::internalError(asyncResp->res);
21123bf4e632SJoseph Reynolds                             return;
21133bf4e632SJoseph Reynolds                         }
2114002d39b4SEd Tanous                         asyncResp->res.jsonValue["PasswordChangeRequired"] =
21153bf4e632SJoseph Reynolds                             *userPasswordExpired;
21163bf4e632SJoseph Reynolds                     }
2117c7229815SAbhishek Patel                     else if (property.first == "UserGroups")
2118c7229815SAbhishek Patel                     {
2119c7229815SAbhishek Patel                         const std::vector<std::string>* userGroups =
2120c7229815SAbhishek Patel                             std::get_if<std::vector<std::string>>(
2121c7229815SAbhishek Patel                                 &property.second);
2122c7229815SAbhishek Patel                         if (userGroups == nullptr)
2123c7229815SAbhishek Patel                         {
212462598e31SEd Tanous                             BMCWEB_LOG_ERROR(
212562598e31SEd Tanous                                 "userGroups wasn't a string vector");
2126c7229815SAbhishek Patel                             messages::internalError(asyncResp->res);
2127c7229815SAbhishek Patel                             return;
2128c7229815SAbhishek Patel                         }
2129c7229815SAbhishek Patel                         if (!translateUserGroup(*userGroups, asyncResp->res))
2130c7229815SAbhishek Patel                         {
213162598e31SEd Tanous                             BMCWEB_LOG_ERROR("userGroups mapping failed");
2132c7229815SAbhishek Patel                             messages::internalError(asyncResp->res);
2133c7229815SAbhishek Patel                             return;
2134c7229815SAbhishek Patel                         }
2135c7229815SAbhishek Patel                     }
213665b0dc32SEd Tanous                 }
213765b0dc32SEd Tanous             }
213865b0dc32SEd Tanous         }
213965b0dc32SEd Tanous 
21403b32780dSEd Tanous         asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
21413b32780dSEd Tanous             "/redfish/v1/AccountService/Accounts/{}", accountName);
2142b9b2e0b2SEd Tanous         asyncResp->res.jsonValue["Id"] = accountName;
2143b9b2e0b2SEd Tanous         asyncResp->res.jsonValue["UserName"] = accountName;
21445eb468daSGeorge Liu     });
21451ef4c342SEd Tanous }
2146a840879dSEd Tanous 
21471ef4c342SEd Tanous inline void
214820fc307fSGunnar Mills     handleAccountDelete(App& app, const crow::Request& req,
21496c51eab1SEd Tanous                         const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
21501ef4c342SEd Tanous                         const std::string& username)
21511ef4c342SEd Tanous {
21523ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
215345ca1b86SEd Tanous     {
215445ca1b86SEd Tanous         return;
215545ca1b86SEd Tanous     }
21561ef4c342SEd Tanous 
21571ef4c342SEd Tanous #ifdef BMCWEB_INSECURE_DISABLE_AUTHENTICATION
2158031514fbSJunLin Chen     // If authentication is disabled, there are no user accounts
2159d8a5d5d8SJiaqing Zhao     messages::resourceNotFound(asyncResp->res, "ManagerAccount", username);
2160031514fbSJunLin Chen     return;
2161031514fbSJunLin Chen 
21621ef4c342SEd Tanous #endif // BMCWEB_INSECURE_DISABLE_AUTHENTICATION
21631ef4c342SEd Tanous     sdbusplus::message::object_path tempObjPath(rootUserDbusPath);
21641ef4c342SEd Tanous     tempObjPath /= username;
21651ef4c342SEd Tanous     const std::string userPath(tempObjPath);
21661ef4c342SEd Tanous 
21671ef4c342SEd Tanous     crow::connections::systemBus->async_method_call(
21685e7e2dc5SEd Tanous         [asyncResp, username](const boost::system::error_code& ec) {
21691ef4c342SEd Tanous         if (ec)
21701ef4c342SEd Tanous         {
2171d8a5d5d8SJiaqing Zhao             messages::resourceNotFound(asyncResp->res, "ManagerAccount",
21721ef4c342SEd Tanous                                        username);
21731ef4c342SEd Tanous             return;
21741ef4c342SEd Tanous         }
21751ef4c342SEd Tanous 
21761ef4c342SEd Tanous         messages::accountRemoved(asyncResp->res);
21771ef4c342SEd Tanous     },
21781ef4c342SEd Tanous         "xyz.openbmc_project.User.Manager", userPath,
21791ef4c342SEd Tanous         "xyz.openbmc_project.Object.Delete", "Delete");
21801ef4c342SEd Tanous }
21811ef4c342SEd Tanous 
21821ef4c342SEd Tanous inline void
21831ef4c342SEd Tanous     handleAccountPatch(App& app, const crow::Request& req,
21841ef4c342SEd Tanous                        const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
21851ef4c342SEd Tanous                        const std::string& username)
21861ef4c342SEd Tanous {
21871ef4c342SEd Tanous     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
21881ef4c342SEd Tanous     {
21891ef4c342SEd Tanous         return;
21901ef4c342SEd Tanous     }
21911ef4c342SEd Tanous #ifdef BMCWEB_INSECURE_DISABLE_AUTHENTICATION
21921ef4c342SEd Tanous     // If authentication is disabled, there are no user accounts
2193d8a5d5d8SJiaqing Zhao     messages::resourceNotFound(asyncResp->res, "ManagerAccount", username);
21941ef4c342SEd Tanous     return;
21951ef4c342SEd Tanous 
21961ef4c342SEd Tanous #endif // BMCWEB_INSECURE_DISABLE_AUTHENTICATION
2197a24526dcSEd Tanous     std::optional<std::string> newUserName;
2198a24526dcSEd Tanous     std::optional<std::string> password;
2199a24526dcSEd Tanous     std::optional<bool> enabled;
2200a24526dcSEd Tanous     std::optional<std::string> roleId;
220124c8542dSRatan Gupta     std::optional<bool> locked;
220258345856SAbhishek Patel     std::optional<std::vector<std::string>> accountTypes;
220358345856SAbhishek Patel 
220458345856SAbhishek Patel     bool userSelf = (username == req.session->username);
2205e9cc5172SEd Tanous 
2206031514fbSJunLin Chen     if (req.session == nullptr)
2207031514fbSJunLin Chen     {
2208031514fbSJunLin Chen         messages::internalError(asyncResp->res);
2209031514fbSJunLin Chen         return;
2210031514fbSJunLin Chen     }
2211031514fbSJunLin Chen 
2212e9cc5172SEd Tanous     Privileges effectiveUserPrivileges =
22133e72c202SNinad Palsule         redfish::getUserPrivileges(*req.session);
2214e9cc5172SEd Tanous     Privileges configureUsers = {"ConfigureUsers"};
2215e9cc5172SEd Tanous     bool userHasConfigureUsers =
2216e9cc5172SEd Tanous         effectiveUserPrivileges.isSupersetOf(configureUsers);
2217e9cc5172SEd Tanous     if (userHasConfigureUsers)
2218e9cc5172SEd Tanous     {
2219e9cc5172SEd Tanous         // Users with ConfigureUsers can modify for all users
222058345856SAbhishek Patel         if (!json_util::readJsonPatch(
222158345856SAbhishek Patel                 req, asyncResp->res, "UserName", newUserName, "Password",
222258345856SAbhishek Patel                 password, "RoleId", roleId, "Enabled", enabled, "Locked",
222358345856SAbhishek Patel                 locked, "AccountTypes", accountTypes))
2224a840879dSEd Tanous         {
2225a840879dSEd Tanous             return;
2226a840879dSEd Tanous         }
2227e9cc5172SEd Tanous     }
2228e9cc5172SEd Tanous     else
2229900f9497SJoseph Reynolds     {
2230e9cc5172SEd Tanous         // ConfigureSelf accounts can only modify their own account
223158345856SAbhishek Patel         if (!userSelf)
2232900f9497SJoseph Reynolds         {
2233900f9497SJoseph Reynolds             messages::insufficientPrivilege(asyncResp->res);
2234900f9497SJoseph Reynolds             return;
2235900f9497SJoseph Reynolds         }
2236031514fbSJunLin Chen 
2237e9cc5172SEd Tanous         // ConfigureSelf accounts can only modify their password
22381ef4c342SEd Tanous         if (!json_util::readJsonPatch(req, asyncResp->res, "Password",
22391ef4c342SEd Tanous                                       password))
2240e9cc5172SEd Tanous         {
2241e9cc5172SEd Tanous             return;
2242e9cc5172SEd Tanous         }
2243900f9497SJoseph Reynolds     }
2244900f9497SJoseph Reynolds 
224566b5ca76Sjayaprakash Mutyala     // if user name is not provided in the patch method or if it
22466c51eab1SEd Tanous     // matches the user name in the URI, then we are treating it as
22476c51eab1SEd Tanous     // updating user properties other then username. If username
22486c51eab1SEd Tanous     // provided doesn't match the URI, then we are treating this as
22496c51eab1SEd Tanous     // user rename request.
225066b5ca76Sjayaprakash Mutyala     if (!newUserName || (newUserName.value() == username))
2251a840879dSEd Tanous     {
22521ef4c342SEd Tanous         updateUserProperties(asyncResp, username, password, enabled, roleId,
225358345856SAbhishek Patel                              locked, accountTypes, userSelf);
225484e12cb7SAppaRao Puli         return;
225584e12cb7SAppaRao Puli     }
225684e12cb7SAppaRao Puli     crow::connections::systemBus->async_method_call(
22576c51eab1SEd Tanous         [asyncResp, username, password(std::move(password)),
22581ef4c342SEd Tanous          roleId(std::move(roleId)), enabled, newUser{std::string(*newUserName)},
225958345856SAbhishek Patel          locked, userSelf, accountTypes(std::move(accountTypes))](
2260e81de512SEd Tanous             const boost::system::error_code& ec, sdbusplus::message_t& m) {
226184e12cb7SAppaRao Puli         if (ec)
226284e12cb7SAppaRao Puli         {
2263002d39b4SEd Tanous             userErrorMessageHandler(m.get_error(), asyncResp, newUser,
2264002d39b4SEd Tanous                                     username);
2265a840879dSEd Tanous             return;
2266a840879dSEd Tanous         }
2267a840879dSEd Tanous 
2268002d39b4SEd Tanous         updateUserProperties(asyncResp, newUser, password, enabled, roleId,
226958345856SAbhishek Patel                              locked, accountTypes, userSelf);
227084e12cb7SAppaRao Puli     },
22711ef4c342SEd Tanous         "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
227284e12cb7SAppaRao Puli         "xyz.openbmc_project.User.Manager", "RenameUser", username,
227384e12cb7SAppaRao Puli         *newUserName);
22741ef4c342SEd Tanous }
22751ef4c342SEd Tanous 
22761ef4c342SEd Tanous inline void requestAccountServiceRoutes(App& app)
22771ef4c342SEd Tanous {
22781ef4c342SEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/AccountService/")
22794c7d4d33SEd Tanous         .privileges(redfish::privileges::headAccountService)
22804c7d4d33SEd Tanous         .methods(boost::beast::http::verb::head)(
22814c7d4d33SEd Tanous             std::bind_front(handleAccountServiceHead, std::ref(app)));
22824c7d4d33SEd Tanous 
22834c7d4d33SEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/AccountService/")
22841ef4c342SEd Tanous         .privileges(redfish::privileges::getAccountService)
22851ef4c342SEd Tanous         .methods(boost::beast::http::verb::get)(
22861ef4c342SEd Tanous             std::bind_front(handleAccountServiceGet, std::ref(app)));
22871ef4c342SEd Tanous 
22881ef4c342SEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/AccountService/")
22891ef4c342SEd Tanous         .privileges(redfish::privileges::patchAccountService)
22901ef4c342SEd Tanous         .methods(boost::beast::http::verb::patch)(
22911ef4c342SEd Tanous             std::bind_front(handleAccountServicePatch, std::ref(app)));
22921ef4c342SEd Tanous 
22931ef4c342SEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/")
22944c7d4d33SEd Tanous         .privileges(redfish::privileges::headManagerAccountCollection)
22954c7d4d33SEd Tanous         .methods(boost::beast::http::verb::head)(
22964c7d4d33SEd Tanous             std::bind_front(handleAccountCollectionHead, std::ref(app)));
22974c7d4d33SEd Tanous 
22984c7d4d33SEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/")
22991ef4c342SEd Tanous         .privileges(redfish::privileges::getManagerAccountCollection)
23001ef4c342SEd Tanous         .methods(boost::beast::http::verb::get)(
23011ef4c342SEd Tanous             std::bind_front(handleAccountCollectionGet, std::ref(app)));
23021ef4c342SEd Tanous 
23031ef4c342SEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/")
23041ef4c342SEd Tanous         .privileges(redfish::privileges::postManagerAccountCollection)
23051ef4c342SEd Tanous         .methods(boost::beast::http::verb::post)(
23061ef4c342SEd Tanous             std::bind_front(handleAccountCollectionPost, std::ref(app)));
23071ef4c342SEd Tanous 
23081ef4c342SEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/<str>/")
23094c7d4d33SEd Tanous         .privileges(redfish::privileges::headManagerAccount)
23104c7d4d33SEd Tanous         .methods(boost::beast::http::verb::head)(
23114c7d4d33SEd Tanous             std::bind_front(handleAccountHead, std::ref(app)));
23124c7d4d33SEd Tanous 
23134c7d4d33SEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/<str>/")
23141ef4c342SEd Tanous         .privileges(redfish::privileges::getManagerAccount)
23151ef4c342SEd Tanous         .methods(boost::beast::http::verb::get)(
23161ef4c342SEd Tanous             std::bind_front(handleAccountGet, std::ref(app)));
23171ef4c342SEd Tanous 
23181ef4c342SEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/<str>/")
23191ef4c342SEd Tanous         // TODO this privilege should be using the generated endpoints, but
23201ef4c342SEd Tanous         // because of the special handling of ConfigureSelf, it's not able to
23211ef4c342SEd Tanous         // yet
23221ef4c342SEd Tanous         .privileges({{"ConfigureUsers"}, {"ConfigureSelf"}})
23231ef4c342SEd Tanous         .methods(boost::beast::http::verb::patch)(
23241ef4c342SEd Tanous             std::bind_front(handleAccountPatch, std::ref(app)));
232584e12cb7SAppaRao Puli 
23266c51eab1SEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/<str>/")
2327ed398213SEd Tanous         .privileges(redfish::privileges::deleteManagerAccount)
23286c51eab1SEd Tanous         .methods(boost::beast::http::verb::delete_)(
232920fc307fSGunnar Mills             std::bind_front(handleAccountDelete, std::ref(app)));
233006e086d9SEd Tanous }
233188d16c9aSLewanczyk, Dawid 
233288d16c9aSLewanczyk, Dawid } // namespace redfish
2333