xref: /openbmc/bmcweb/features/redfish/lib/account_service.hpp (revision e9f120141c8d2a1404660e46ce2126c83521405d)
188d16c9aSLewanczyk, Dawid /*
26be832e2SEd Tanous Copyright (c) 2018 Intel Corporation
36be832e2SEd Tanous 
46be832e2SEd Tanous Licensed under the Apache License, Version 2.0 (the "License");
56be832e2SEd Tanous you may not use this file except in compliance with the License.
66be832e2SEd Tanous You may obtain a copy of the License at
76be832e2SEd Tanous 
86be832e2SEd Tanous       http://www.apache.org/licenses/LICENSE-2.0
96be832e2SEd Tanous 
106be832e2SEd Tanous Unless required by applicable law or agreed to in writing, software
116be832e2SEd Tanous distributed under the License is distributed on an "AS IS" BASIS,
126be832e2SEd Tanous WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
136be832e2SEd Tanous See the License for the specific language governing permissions and
146be832e2SEd Tanous limitations under the License.
1588d16c9aSLewanczyk, Dawid */
1688d16c9aSLewanczyk, Dawid #pragma once
1788d16c9aSLewanczyk, Dawid 
183ccb3adbSEd Tanous #include "app.hpp"
19a0735a4eSGunnar Mills #include "boost_formatters.hpp"
201aa375b8SEd Tanous #include "certificate_service.hpp"
213ccb3adbSEd Tanous #include "dbus_utility.hpp"
223ccb3adbSEd Tanous #include "error_messages.hpp"
230ec8b83dSEd Tanous #include "generated/enums/account_service.hpp"
243ccb3adbSEd Tanous #include "persistent_data.hpp"
253ccb3adbSEd Tanous #include "query.hpp"
260ec8b83dSEd Tanous #include "registries/privilege_registry.hpp"
273281bcf1SEd Tanous #include "sessions.hpp"
281aa375b8SEd Tanous #include "utils/collection.hpp"
293ccb3adbSEd Tanous #include "utils/dbus_utils.hpp"
303ccb3adbSEd Tanous #include "utils/json_utils.hpp"
310ec8b83dSEd Tanous 
321aa375b8SEd Tanous #include <boost/url/format.hpp>
331aa375b8SEd Tanous #include <boost/url/url.hpp>
341e1e598dSJonathan Doman #include <sdbusplus/asio/property.hpp>
35d1bde9e5SKrzysztof Grobelny #include <sdbusplus/unpack_properties.hpp>
361214b7e7SGunnar Mills 
372b73119cSGeorge Liu #include <array>
381aa375b8SEd Tanous #include <memory>
39c7229815SAbhishek Patel #include <optional>
403544d2a7SEd Tanous #include <ranges>
41c7229815SAbhishek Patel #include <string>
422b73119cSGeorge Liu #include <string_view>
4320fa6a2cSEd Tanous #include <utility>
44c7229815SAbhishek Patel #include <vector>
45c7229815SAbhishek Patel 
461abe55efSEd Tanous namespace redfish
471abe55efSEd Tanous {
4888d16c9aSLewanczyk, Dawid 
4923a21a1cSEd Tanous constexpr const char* ldapConfigObjectName =
506973a582SRatan Gupta     "/xyz/openbmc_project/user/ldap/openldap";
512c70f800SEd Tanous constexpr const char* adConfigObject =
52ab828d7cSRatan Gupta     "/xyz/openbmc_project/user/ldap/active_directory";
53ab828d7cSRatan Gupta 
54b477fd44SP Dheeraj Srujan Kumar constexpr const char* rootUserDbusPath = "/xyz/openbmc_project/user/";
556973a582SRatan Gupta constexpr const char* ldapRootObject = "/xyz/openbmc_project/user/ldap";
566973a582SRatan Gupta constexpr const char* ldapDbusService = "xyz.openbmc_project.Ldap.Config";
576973a582SRatan Gupta constexpr const char* ldapConfigInterface =
586973a582SRatan Gupta     "xyz.openbmc_project.User.Ldap.Config";
596973a582SRatan Gupta constexpr const char* ldapCreateInterface =
606973a582SRatan Gupta     "xyz.openbmc_project.User.Ldap.Create";
616973a582SRatan Gupta constexpr const char* ldapEnableInterface = "xyz.openbmc_project.Object.Enable";
6206785244SRatan Gupta constexpr const char* ldapPrivMapperInterface =
6306785244SRatan Gupta     "xyz.openbmc_project.User.PrivilegeMapper";
646973a582SRatan Gupta 
6554fc587aSNagaraju Goruganti struct LDAPRoleMapData
6654fc587aSNagaraju Goruganti {
6754fc587aSNagaraju Goruganti     std::string groupName;
6854fc587aSNagaraju Goruganti     std::string privilege;
6954fc587aSNagaraju Goruganti };
7054fc587aSNagaraju Goruganti 
716973a582SRatan Gupta struct LDAPConfigData
726973a582SRatan Gupta {
7347f2934cSEd Tanous     std::string uri;
7447f2934cSEd Tanous     std::string bindDN;
7547f2934cSEd Tanous     std::string baseDN;
7647f2934cSEd Tanous     std::string searchScope;
7747f2934cSEd Tanous     std::string serverType;
786973a582SRatan Gupta     bool serviceEnabled = false;
7947f2934cSEd Tanous     std::string userNameAttribute;
8047f2934cSEd Tanous     std::string groupAttribute;
8154fc587aSNagaraju Goruganti     std::vector<std::pair<std::string, LDAPRoleMapData>> groupRoleList;
826973a582SRatan Gupta };
836973a582SRatan Gupta 
8454fc587aSNagaraju Goruganti inline std::string getRoleIdFromPrivilege(std::string_view role)
8584e12cb7SAppaRao Puli {
8684e12cb7SAppaRao Puli     if (role == "priv-admin")
8784e12cb7SAppaRao Puli     {
8884e12cb7SAppaRao Puli         return "Administrator";
8984e12cb7SAppaRao Puli     }
903174e4dfSEd Tanous     if (role == "priv-user")
9184e12cb7SAppaRao Puli     {
92c80fee55SAppaRao Puli         return "ReadOnly";
9384e12cb7SAppaRao Puli     }
943174e4dfSEd Tanous     if (role == "priv-operator")
9584e12cb7SAppaRao Puli     {
9684e12cb7SAppaRao Puli         return "Operator";
9784e12cb7SAppaRao Puli     }
9884e12cb7SAppaRao Puli     return "";
9984e12cb7SAppaRao Puli }
10054fc587aSNagaraju Goruganti inline std::string getPrivilegeFromRoleId(std::string_view role)
10184e12cb7SAppaRao Puli {
10284e12cb7SAppaRao Puli     if (role == "Administrator")
10384e12cb7SAppaRao Puli     {
10484e12cb7SAppaRao Puli         return "priv-admin";
10584e12cb7SAppaRao Puli     }
1063174e4dfSEd Tanous     if (role == "ReadOnly")
10784e12cb7SAppaRao Puli     {
10884e12cb7SAppaRao Puli         return "priv-user";
10984e12cb7SAppaRao Puli     }
1103174e4dfSEd Tanous     if (role == "Operator")
11184e12cb7SAppaRao Puli     {
11284e12cb7SAppaRao Puli         return "priv-operator";
11384e12cb7SAppaRao Puli     }
11484e12cb7SAppaRao Puli     return "";
11584e12cb7SAppaRao Puli }
116b9b2e0b2SEd Tanous 
117c7229815SAbhishek Patel /**
118c7229815SAbhishek Patel  * @brief Maps user group names retrieved from D-Bus object to
119c7229815SAbhishek Patel  * Account Types.
120c7229815SAbhishek Patel  *
121c7229815SAbhishek Patel  * @param[in] userGroups List of User groups
122c7229815SAbhishek Patel  * @param[out] res AccountTypes populated
123c7229815SAbhishek Patel  *
124c7229815SAbhishek Patel  * @return true in case of success, false if UserGroups contains
125c7229815SAbhishek Patel  * invalid group name(s).
126c7229815SAbhishek Patel  */
127c7229815SAbhishek Patel inline bool translateUserGroup(const std::vector<std::string>& userGroups,
128c7229815SAbhishek Patel                                crow::Response& res)
129c7229815SAbhishek Patel {
130c7229815SAbhishek Patel     std::vector<std::string> accountTypes;
131c7229815SAbhishek Patel     for (const auto& userGroup : userGroups)
132c7229815SAbhishek Patel     {
133c7229815SAbhishek Patel         if (userGroup == "redfish")
134c7229815SAbhishek Patel         {
135c7229815SAbhishek Patel             accountTypes.emplace_back("Redfish");
136c7229815SAbhishek Patel             accountTypes.emplace_back("WebUI");
137c7229815SAbhishek Patel         }
138c7229815SAbhishek Patel         else if (userGroup == "ipmi")
139c7229815SAbhishek Patel         {
140c7229815SAbhishek Patel             accountTypes.emplace_back("IPMI");
141c7229815SAbhishek Patel         }
142c7229815SAbhishek Patel         else if (userGroup == "ssh")
143c7229815SAbhishek Patel         {
144c7229815SAbhishek Patel             accountTypes.emplace_back("ManagerConsole");
145c7229815SAbhishek Patel         }
1463e72c202SNinad Palsule         else if (userGroup == "hostconsole")
1473e72c202SNinad Palsule         {
1483e72c202SNinad Palsule             // The hostconsole group controls who can access the host console
1493e72c202SNinad Palsule             // port via ssh and websocket.
1503e72c202SNinad Palsule             accountTypes.emplace_back("HostConsole");
1513e72c202SNinad Palsule         }
152c7229815SAbhishek Patel         else if (userGroup == "web")
153c7229815SAbhishek Patel         {
154c7229815SAbhishek Patel             // 'web' is one of the valid groups in the UserGroups property of
155c7229815SAbhishek Patel             // the user account in the D-Bus object. This group is currently not
156c7229815SAbhishek Patel             // doing anything, and is considered to be equivalent to 'redfish'.
157c7229815SAbhishek Patel             // 'redfish' user group is mapped to 'Redfish'and 'WebUI'
158c7229815SAbhishek Patel             // AccountTypes, so do nothing here...
159c7229815SAbhishek Patel         }
160c7229815SAbhishek Patel         else
161c7229815SAbhishek Patel         {
1628ece0e45SEd Tanous             // Invalid user group name. Caller throws an exception.
163c7229815SAbhishek Patel             return false;
164c7229815SAbhishek Patel         }
165c7229815SAbhishek Patel     }
166c7229815SAbhishek Patel 
167c7229815SAbhishek Patel     res.jsonValue["AccountTypes"] = std::move(accountTypes);
168c7229815SAbhishek Patel     return true;
169c7229815SAbhishek Patel }
170c7229815SAbhishek Patel 
17158345856SAbhishek Patel /**
17258345856SAbhishek Patel  * @brief Builds User Groups from the Account Types
17358345856SAbhishek Patel  *
17458345856SAbhishek Patel  * @param[in] asyncResp Async Response
17558345856SAbhishek Patel  * @param[in] accountTypes List of Account Types
17658345856SAbhishek Patel  * @param[out] userGroups List of User Groups mapped from Account Types
17758345856SAbhishek Patel  *
17858345856SAbhishek Patel  * @return true if Account Types mapped to User Groups, false otherwise.
17958345856SAbhishek Patel  */
180bd79bce8SPatrick Williams inline bool getUserGroupFromAccountType(
181bd79bce8SPatrick Williams     crow::Response& res, const std::vector<std::string>& accountTypes,
18258345856SAbhishek Patel     std::vector<std::string>& userGroups)
18358345856SAbhishek Patel {
18458345856SAbhishek Patel     // Need both Redfish and WebUI Account Types to map to 'redfish' User Group
18558345856SAbhishek Patel     bool redfishType = false;
18658345856SAbhishek Patel     bool webUIType = false;
18758345856SAbhishek Patel 
18858345856SAbhishek Patel     for (const auto& accountType : accountTypes)
18958345856SAbhishek Patel     {
19058345856SAbhishek Patel         if (accountType == "Redfish")
19158345856SAbhishek Patel         {
19258345856SAbhishek Patel             redfishType = true;
19358345856SAbhishek Patel         }
19458345856SAbhishek Patel         else if (accountType == "WebUI")
19558345856SAbhishek Patel         {
19658345856SAbhishek Patel             webUIType = true;
19758345856SAbhishek Patel         }
19858345856SAbhishek Patel         else if (accountType == "IPMI")
19958345856SAbhishek Patel         {
20058345856SAbhishek Patel             userGroups.emplace_back("ipmi");
20158345856SAbhishek Patel         }
20258345856SAbhishek Patel         else if (accountType == "HostConsole")
20358345856SAbhishek Patel         {
20458345856SAbhishek Patel             userGroups.emplace_back("hostconsole");
20558345856SAbhishek Patel         }
20658345856SAbhishek Patel         else if (accountType == "ManagerConsole")
20758345856SAbhishek Patel         {
20858345856SAbhishek Patel             userGroups.emplace_back("ssh");
20958345856SAbhishek Patel         }
21058345856SAbhishek Patel         else
21158345856SAbhishek Patel         {
21258345856SAbhishek Patel             // Invalid Account Type
21358345856SAbhishek Patel             messages::propertyValueNotInList(res, "AccountTypes", accountType);
21458345856SAbhishek Patel             return false;
21558345856SAbhishek Patel         }
21658345856SAbhishek Patel     }
21758345856SAbhishek Patel 
21858345856SAbhishek Patel     // Both  Redfish and WebUI Account Types are needed to PATCH
21958345856SAbhishek Patel     if (redfishType ^ webUIType)
22058345856SAbhishek Patel     {
22162598e31SEd Tanous         BMCWEB_LOG_ERROR(
22262598e31SEd Tanous             "Missing Redfish or WebUI Account Type to set redfish User Group");
22358345856SAbhishek Patel         messages::strictAccountTypes(res, "AccountTypes");
22458345856SAbhishek Patel         return false;
22558345856SAbhishek Patel     }
22658345856SAbhishek Patel 
22758345856SAbhishek Patel     if (redfishType && webUIType)
22858345856SAbhishek Patel     {
22958345856SAbhishek Patel         userGroups.emplace_back("redfish");
23058345856SAbhishek Patel     }
23158345856SAbhishek Patel 
23258345856SAbhishek Patel     return true;
23358345856SAbhishek Patel }
23458345856SAbhishek Patel 
23558345856SAbhishek Patel /**
23658345856SAbhishek Patel  * @brief Sets UserGroups property of the user based on the Account Types
23758345856SAbhishek Patel  *
23858345856SAbhishek Patel  * @param[in] accountTypes List of User Account Types
23958345856SAbhishek Patel  * @param[in] asyncResp Async Response
24058345856SAbhishek Patel  * @param[in] dbusObjectPath D-Bus Object Path
24158345856SAbhishek Patel  * @param[in] userSelf true if User is updating OWN Account Types
24258345856SAbhishek Patel  */
24358345856SAbhishek Patel inline void
24458345856SAbhishek Patel     patchAccountTypes(const std::vector<std::string>& accountTypes,
24558345856SAbhishek Patel                       const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
24658345856SAbhishek Patel                       const std::string& dbusObjectPath, bool userSelf)
24758345856SAbhishek Patel {
24858345856SAbhishek Patel     // Check if User is disabling own Redfish Account Type
24958345856SAbhishek Patel     if (userSelf &&
25058345856SAbhishek Patel         (accountTypes.cend() ==
25158345856SAbhishek Patel          std::find(accountTypes.cbegin(), accountTypes.cend(), "Redfish")))
25258345856SAbhishek Patel     {
25362598e31SEd Tanous         BMCWEB_LOG_ERROR(
25462598e31SEd Tanous             "User disabling OWN Redfish Account Type is not allowed");
25558345856SAbhishek Patel         messages::strictAccountTypes(asyncResp->res, "AccountTypes");
25658345856SAbhishek Patel         return;
25758345856SAbhishek Patel     }
25858345856SAbhishek Patel 
25958345856SAbhishek Patel     std::vector<std::string> updatedUserGroups;
26058345856SAbhishek Patel     if (!getUserGroupFromAccountType(asyncResp->res, accountTypes,
26158345856SAbhishek Patel                                      updatedUserGroups))
26258345856SAbhishek Patel     {
26358345856SAbhishek Patel         // Problem in mapping Account Types to User Groups, Error already
26458345856SAbhishek Patel         // logged.
26558345856SAbhishek Patel         return;
26658345856SAbhishek Patel     }
267e93abac6SGinu George     setDbusProperty(asyncResp, "AccountTypes",
268e93abac6SGinu George                     "xyz.openbmc_project.User.Manager", dbusObjectPath,
269e93abac6SGinu George                     "xyz.openbmc_project.User.Attributes", "UserGroups",
270e93abac6SGinu George                     updatedUserGroups);
27158345856SAbhishek Patel }
27258345856SAbhishek Patel 
2738d1b46d7Szhanghch05 inline void userErrorMessageHandler(
2748d1b46d7Szhanghch05     const sd_bus_error* e, const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2758d1b46d7Szhanghch05     const std::string& newUser, const std::string& username)
27666b5ca76Sjayaprakash Mutyala {
27766b5ca76Sjayaprakash Mutyala     if (e == nullptr)
27866b5ca76Sjayaprakash Mutyala     {
27966b5ca76Sjayaprakash Mutyala         messages::internalError(asyncResp->res);
28066b5ca76Sjayaprakash Mutyala         return;
28166b5ca76Sjayaprakash Mutyala     }
28266b5ca76Sjayaprakash Mutyala 
283055806b3SManojkiran Eda     const char* errorMessage = e->name;
28466b5ca76Sjayaprakash Mutyala     if (strcmp(errorMessage,
28566b5ca76Sjayaprakash Mutyala                "xyz.openbmc_project.User.Common.Error.UserNameExists") == 0)
28666b5ca76Sjayaprakash Mutyala     {
287d8a5d5d8SJiaqing Zhao         messages::resourceAlreadyExists(asyncResp->res, "ManagerAccount",
28866b5ca76Sjayaprakash Mutyala                                         "UserName", newUser);
28966b5ca76Sjayaprakash Mutyala     }
29066b5ca76Sjayaprakash Mutyala     else if (strcmp(errorMessage, "xyz.openbmc_project.User.Common.Error."
29166b5ca76Sjayaprakash Mutyala                                   "UserNameDoesNotExist") == 0)
29266b5ca76Sjayaprakash Mutyala     {
293d8a5d5d8SJiaqing Zhao         messages::resourceNotFound(asyncResp->res, "ManagerAccount", username);
29466b5ca76Sjayaprakash Mutyala     }
295d4d25793SEd Tanous     else if ((strcmp(errorMessage,
296d4d25793SEd Tanous                      "xyz.openbmc_project.Common.Error.InvalidArgument") ==
297d4d25793SEd Tanous               0) ||
2980fda0f12SGeorge Liu              (strcmp(
2990fda0f12SGeorge Liu                   errorMessage,
3000fda0f12SGeorge Liu                   "xyz.openbmc_project.User.Common.Error.UserNameGroupFail") ==
3010fda0f12SGeorge Liu               0))
30266b5ca76Sjayaprakash Mutyala     {
30366b5ca76Sjayaprakash Mutyala         messages::propertyValueFormatError(asyncResp->res, newUser, "UserName");
30466b5ca76Sjayaprakash Mutyala     }
30566b5ca76Sjayaprakash Mutyala     else if (strcmp(errorMessage,
30666b5ca76Sjayaprakash Mutyala                     "xyz.openbmc_project.User.Common.Error.NoResource") == 0)
30766b5ca76Sjayaprakash Mutyala     {
30866b5ca76Sjayaprakash Mutyala         messages::createLimitReachedForResource(asyncResp->res);
30966b5ca76Sjayaprakash Mutyala     }
31066b5ca76Sjayaprakash Mutyala     else
31166b5ca76Sjayaprakash Mutyala     {
312b8ad583fSGunnar Mills         BMCWEB_LOG_ERROR("DBUS response error {}", errorMessage);
31366b5ca76Sjayaprakash Mutyala         messages::internalError(asyncResp->res);
31466b5ca76Sjayaprakash Mutyala     }
31566b5ca76Sjayaprakash Mutyala }
31666b5ca76Sjayaprakash Mutyala 
31781ce609eSEd Tanous inline void parseLDAPConfigData(nlohmann::json& jsonResponse,
318ab828d7cSRatan Gupta                                 const LDAPConfigData& confData,
319ab828d7cSRatan Gupta                                 const std::string& ldapType)
3206973a582SRatan Gupta {
32149cc263fSEd Tanous     nlohmann::json::object_t ldap;
3221476687dSEd Tanous     ldap["ServiceEnabled"] = confData.serviceEnabled;
32349cc263fSEd Tanous     nlohmann::json::array_t serviceAddresses;
32449cc263fSEd Tanous     serviceAddresses.emplace_back(confData.uri);
32549cc263fSEd Tanous     ldap["ServiceAddresses"] = std::move(serviceAddresses);
32649cc263fSEd Tanous 
32749cc263fSEd Tanous     nlohmann::json::object_t authentication;
32849cc263fSEd Tanous     authentication["AuthenticationType"] =
3290ec8b83dSEd Tanous         account_service::AuthenticationTypes::UsernameAndPassword;
33049cc263fSEd Tanous     authentication["Username"] = confData.bindDN;
33149cc263fSEd Tanous     authentication["Password"] = nullptr;
33249cc263fSEd Tanous     ldap["Authentication"] = std::move(authentication);
3331476687dSEd Tanous 
33449cc263fSEd Tanous     nlohmann::json::object_t ldapService;
33549cc263fSEd Tanous     nlohmann::json::object_t searchSettings;
33649cc263fSEd Tanous     nlohmann::json::array_t baseDistinguishedNames;
33749cc263fSEd Tanous     baseDistinguishedNames.emplace_back(confData.baseDN);
3381476687dSEd Tanous 
33949cc263fSEd Tanous     searchSettings["BaseDistinguishedNames"] =
34049cc263fSEd Tanous         std::move(baseDistinguishedNames);
34149cc263fSEd Tanous     searchSettings["UsernameAttribute"] = confData.userNameAttribute;
34249cc263fSEd Tanous     searchSettings["GroupsAttribute"] = confData.groupAttribute;
34349cc263fSEd Tanous     ldapService["SearchSettings"] = std::move(searchSettings);
34449cc263fSEd Tanous     ldap["LDAPService"] = std::move(ldapService);
34549cc263fSEd Tanous 
34649cc263fSEd Tanous     nlohmann::json::array_t roleMapArray;
3479eb808c1SEd Tanous     for (const auto& obj : confData.groupRoleList)
34854fc587aSNagaraju Goruganti     {
34962598e31SEd Tanous         BMCWEB_LOG_DEBUG("Pushing the data groupName={}", obj.second.groupName);
350613dabeaSEd Tanous 
351613dabeaSEd Tanous         nlohmann::json::object_t remoteGroup;
352613dabeaSEd Tanous         remoteGroup["RemoteGroup"] = obj.second.groupName;
353329f0348SJorge Cisneros         remoteGroup["LocalRole"] = getRoleIdFromPrivilege(obj.second.privilege);
354329f0348SJorge Cisneros         roleMapArray.emplace_back(std::move(remoteGroup));
35554fc587aSNagaraju Goruganti     }
35649cc263fSEd Tanous 
35749cc263fSEd Tanous     ldap["RemoteRoleMapping"] = std::move(roleMapArray);
35849cc263fSEd Tanous 
35949cc263fSEd Tanous     jsonResponse[ldapType].update(ldap);
3606973a582SRatan Gupta }
3616973a582SRatan Gupta 
3626973a582SRatan Gupta /**
36306785244SRatan Gupta  *  @brief validates given JSON input and then calls appropriate method to
36406785244SRatan Gupta  * create, to delete or to set Rolemapping object based on the given input.
36506785244SRatan Gupta  *
36606785244SRatan Gupta  */
36723a21a1cSEd Tanous inline void handleRoleMapPatch(
3688d1b46d7Szhanghch05     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
36906785244SRatan Gupta     const std::vector<std::pair<std::string, LDAPRoleMapData>>& roleMapObjData,
370c1019828SEd Tanous     const std::string& serverType,
371c1019828SEd Tanous     std::vector<std::variant<nlohmann::json::object_t, std::nullptr_t>>& input)
37206785244SRatan Gupta {
37306785244SRatan Gupta     for (size_t index = 0; index < input.size(); index++)
37406785244SRatan Gupta     {
375c1019828SEd Tanous         std::variant<nlohmann::json::object_t, std::nullptr_t>& thisJson =
376c1019828SEd Tanous             input[index];
377c1019828SEd Tanous         nlohmann::json::object_t* obj =
378c1019828SEd Tanous             std::get_if<nlohmann::json::object_t>(&thisJson);
379c1019828SEd Tanous         if (obj == nullptr)
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                         }
393bd79bce8SPatrick Williams                         asyncResp->res
394bd79bce8SPatrick Williams                             .jsonValue[serverType]["RemoteRoleMapping"][index] =
395bd79bce8SPatrick Williams                             nullptr;
39606785244SRatan Gupta                     },
39706785244SRatan Gupta                     ldapDbusService, roleMapObjData[index].first,
39806785244SRatan Gupta                     "xyz.openbmc_project.Object.Delete", "Delete");
39906785244SRatan Gupta             }
40006785244SRatan Gupta             else
40106785244SRatan Gupta             {
40262598e31SEd Tanous                 BMCWEB_LOG_ERROR("Can't delete the object");
403bd79bce8SPatrick Williams                 messages::propertyValueTypeError(
404bd79bce8SPatrick Williams                     asyncResp->res, "null",
405bd79bce8SPatrick Williams                     "RemoteRoleMapping/" + std::to_string(index));
40606785244SRatan Gupta                 return;
40706785244SRatan Gupta             }
40806785244SRatan Gupta         }
409c1019828SEd Tanous         else if (obj->empty())
41006785244SRatan Gupta         {
41106785244SRatan Gupta             // Don't do anything for the empty objects,parse next json
41206785244SRatan Gupta             // eg {"RemoteRoleMapping",[{}]}
41306785244SRatan Gupta         }
41406785244SRatan Gupta         else
41506785244SRatan Gupta         {
41606785244SRatan Gupta             // update/create the object
41706785244SRatan Gupta             std::optional<std::string> remoteGroup;
41806785244SRatan Gupta             std::optional<std::string> localRole;
41906785244SRatan Gupta 
420c1019828SEd Tanous             if (!json_util::readJsonObject(*obj, asyncResp->res, "RemoteGroup",
421c1019828SEd Tanous                                            remoteGroup, "LocalRole", localRole))
42206785244SRatan Gupta             {
42306785244SRatan Gupta                 continue;
42406785244SRatan Gupta             }
42506785244SRatan Gupta 
42606785244SRatan Gupta             // Update existing RoleMapping Object
42706785244SRatan Gupta             if (index < roleMapObjData.size())
42806785244SRatan Gupta             {
42962598e31SEd Tanous                 BMCWEB_LOG_DEBUG("Update Role Map Object");
43006785244SRatan Gupta                 // If "RemoteGroup" info is provided
43106785244SRatan Gupta                 if (remoteGroup)
43206785244SRatan Gupta                 {
433d02aad39SEd Tanous                     setDbusProperty(
434e93abac6SGinu George                         asyncResp,
435d02aad39SEd Tanous                         std::format("RemoteRoleMapping/{}/RemoteGroup", index),
436e93abac6SGinu George                         ldapDbusService, roleMapObjData[index].first,
437e93abac6SGinu George                         "xyz.openbmc_project.User.PrivilegeMapperEntry",
438e93abac6SGinu George                         "GroupName", *remoteGroup);
43906785244SRatan Gupta                 }
44006785244SRatan Gupta 
44106785244SRatan Gupta                 // If "LocalRole" info is provided
44206785244SRatan Gupta                 if (localRole)
44306785244SRatan Gupta                 {
4446d0b80beSRavi Teja                     std::string priv = getPrivilegeFromRoleId(*localRole);
4456d0b80beSRavi Teja                     if (priv.empty())
4466d0b80beSRavi Teja                     {
4476d0b80beSRavi Teja                         messages::propertyValueNotInList(
4486d0b80beSRavi Teja                             asyncResp->res, *localRole,
4496d0b80beSRavi Teja                             std::format("RemoteRoleMapping/{}/LocalRole",
4506d0b80beSRavi Teja                                         index));
4516d0b80beSRavi Teja                         return;
4526d0b80beSRavi Teja                     }
453d02aad39SEd Tanous                     setDbusProperty(
454e93abac6SGinu George                         asyncResp,
455d02aad39SEd Tanous                         std::format("RemoteRoleMapping/{}/LocalRole", index),
456e93abac6SGinu George                         ldapDbusService, roleMapObjData[index].first,
457e93abac6SGinu George                         "xyz.openbmc_project.User.PrivilegeMapperEntry",
4586d0b80beSRavi Teja                         "Privilege", priv);
45906785244SRatan Gupta                 }
46006785244SRatan Gupta             }
46106785244SRatan Gupta             // Create a new RoleMapping Object.
46206785244SRatan Gupta             else
46306785244SRatan Gupta             {
46462598e31SEd Tanous                 BMCWEB_LOG_DEBUG(
46562598e31SEd Tanous                     "setRoleMappingProperties: Creating new Object");
466bd79bce8SPatrick Williams                 std::string pathString =
467bd79bce8SPatrick Williams                     "RemoteRoleMapping/" + std::to_string(index);
46806785244SRatan Gupta 
46906785244SRatan Gupta                 if (!localRole)
47006785244SRatan Gupta                 {
47106785244SRatan Gupta                     messages::propertyMissing(asyncResp->res,
47206785244SRatan Gupta                                               pathString + "/LocalRole");
47306785244SRatan Gupta                     continue;
47406785244SRatan Gupta                 }
47506785244SRatan Gupta                 if (!remoteGroup)
47606785244SRatan Gupta                 {
47706785244SRatan Gupta                     messages::propertyMissing(asyncResp->res,
47806785244SRatan Gupta                                               pathString + "/RemoteGroup");
47906785244SRatan Gupta                     continue;
48006785244SRatan Gupta                 }
48106785244SRatan Gupta 
48206785244SRatan Gupta                 std::string dbusObjectPath;
48306785244SRatan Gupta                 if (serverType == "ActiveDirectory")
48406785244SRatan Gupta                 {
4852c70f800SEd Tanous                     dbusObjectPath = adConfigObject;
48606785244SRatan Gupta                 }
48706785244SRatan Gupta                 else if (serverType == "LDAP")
48806785244SRatan Gupta                 {
48923a21a1cSEd Tanous                     dbusObjectPath = ldapConfigObjectName;
49006785244SRatan Gupta                 }
49106785244SRatan Gupta 
49262598e31SEd Tanous                 BMCWEB_LOG_DEBUG("Remote Group={},LocalRole={}", *remoteGroup,
49362598e31SEd Tanous                                  *localRole);
49406785244SRatan Gupta 
49506785244SRatan Gupta                 crow::connections::systemBus->async_method_call(
496271584abSEd Tanous                     [asyncResp, serverType, localRole,
4975e7e2dc5SEd Tanous                      remoteGroup](const boost::system::error_code& ec) {
49806785244SRatan Gupta                         if (ec)
49906785244SRatan Gupta                         {
50062598e31SEd Tanous                             BMCWEB_LOG_ERROR("DBUS response error: {}", ec);
50106785244SRatan Gupta                             messages::internalError(asyncResp->res);
50206785244SRatan Gupta                             return;
50306785244SRatan Gupta                         }
50406785244SRatan Gupta                         nlohmann::json& remoteRoleJson =
50506785244SRatan Gupta                             asyncResp->res
50606785244SRatan Gupta                                 .jsonValue[serverType]["RemoteRoleMapping"];
5071476687dSEd Tanous                         nlohmann::json::object_t roleMapEntry;
5081476687dSEd Tanous                         roleMapEntry["LocalRole"] = *localRole;
5091476687dSEd Tanous                         roleMapEntry["RemoteGroup"] = *remoteGroup;
510b2ba3072SPatrick Williams                         remoteRoleJson.emplace_back(std::move(roleMapEntry));
51106785244SRatan Gupta                     },
51206785244SRatan Gupta                     ldapDbusService, dbusObjectPath, ldapPrivMapperInterface,
5133174e4dfSEd Tanous                     "Create", *remoteGroup,
51406785244SRatan Gupta                     getPrivilegeFromRoleId(std::move(*localRole)));
51506785244SRatan Gupta             }
51606785244SRatan Gupta         }
51706785244SRatan Gupta     }
51806785244SRatan Gupta }
51906785244SRatan Gupta 
52006785244SRatan Gupta /**
5216973a582SRatan Gupta  * Function that retrieves all properties for LDAP config object
5226973a582SRatan Gupta  * into JSON
5236973a582SRatan Gupta  */
5246973a582SRatan Gupta template <typename CallbackFunc>
525bd79bce8SPatrick Williams inline void
526bd79bce8SPatrick Williams     getLDAPConfigData(const std::string& ldapType, CallbackFunc&& callback)
5276973a582SRatan Gupta {
5282b73119cSGeorge Liu     constexpr std::array<std::string_view, 2> interfaces = {
5292b73119cSGeorge Liu         ldapEnableInterface, ldapConfigInterface};
53054fc587aSNagaraju Goruganti 
5312b73119cSGeorge Liu     dbus::utility::getDbusObject(
5322b73119cSGeorge Liu         ldapConfigObjectName, interfaces,
5338cb2c024SEd Tanous         [callback = std::forward<CallbackFunc>(callback),
534c1019828SEd Tanous          ldapType](const boost::system::error_code& ec,
535c1019828SEd Tanous                    const dbus::utility::MapperGetObject& resp) mutable {
53654fc587aSNagaraju Goruganti             if (ec || resp.empty())
53754fc587aSNagaraju Goruganti             {
538bf2ddedeSCarson Labrado                 BMCWEB_LOG_WARNING(
539bd79bce8SPatrick Williams                     "DBUS response error during getting of service name: {}",
540bd79bce8SPatrick Williams                     ec);
54123a21a1cSEd Tanous                 LDAPConfigData empty{};
54223a21a1cSEd Tanous                 callback(false, empty, ldapType);
54354fc587aSNagaraju Goruganti                 return;
54454fc587aSNagaraju Goruganti             }
54554fc587aSNagaraju Goruganti             std::string service = resp.begin()->first;
5465eb468daSGeorge Liu             sdbusplus::message::object_path path(ldapRootObject);
5475eb468daSGeorge Liu             dbus::utility::getManagedObjects(
5485eb468daSGeorge Liu                 service, path,
549bd79bce8SPatrick Williams                 [callback, ldapType](const boost::system::error_code& ec2,
550bd79bce8SPatrick Williams                                      const dbus::utility::ManagedObjectType&
551bd79bce8SPatrick Williams                                          ldapObjects) mutable {
5526973a582SRatan Gupta                     LDAPConfigData confData{};
5538b24275dSEd Tanous                     if (ec2)
5546973a582SRatan Gupta                     {
555ab828d7cSRatan Gupta                         callback(false, confData, ldapType);
556bf2ddedeSCarson Labrado                         BMCWEB_LOG_WARNING("D-Bus responses error: {}", ec2);
5576973a582SRatan Gupta                         return;
5586973a582SRatan Gupta                     }
559ab828d7cSRatan Gupta 
560ab828d7cSRatan Gupta                     std::string ldapDbusType;
56154fc587aSNagaraju Goruganti                     std::string searchString;
56254fc587aSNagaraju Goruganti 
563ab828d7cSRatan Gupta                     if (ldapType == "LDAP")
564ab828d7cSRatan Gupta                     {
5650fda0f12SGeorge Liu                         ldapDbusType =
5660fda0f12SGeorge Liu                             "xyz.openbmc_project.User.Ldap.Config.Type.OpenLdap";
56754fc587aSNagaraju Goruganti                         searchString = "openldap";
568ab828d7cSRatan Gupta                     }
569ab828d7cSRatan Gupta                     else if (ldapType == "ActiveDirectory")
570ab828d7cSRatan Gupta                     {
57154fc587aSNagaraju Goruganti                         ldapDbusType =
5720fda0f12SGeorge Liu                             "xyz.openbmc_project.User.Ldap.Config.Type.ActiveDirectory";
57354fc587aSNagaraju Goruganti                         searchString = "active_directory";
574ab828d7cSRatan Gupta                     }
575ab828d7cSRatan Gupta                     else
576ab828d7cSRatan Gupta                     {
577bd79bce8SPatrick Williams                         BMCWEB_LOG_ERROR(
578bd79bce8SPatrick Williams                             "Can't get the DbusType for the given type={}",
57962598e31SEd Tanous                             ldapType);
580ab828d7cSRatan Gupta                         callback(false, confData, ldapType);
581ab828d7cSRatan Gupta                         return;
582ab828d7cSRatan Gupta                     }
583ab828d7cSRatan Gupta 
584ab828d7cSRatan Gupta                     std::string ldapEnableInterfaceStr = ldapEnableInterface;
585ab828d7cSRatan Gupta                     std::string ldapConfigInterfaceStr = ldapConfigInterface;
586ab828d7cSRatan Gupta 
5876973a582SRatan Gupta                     for (const auto& object : ldapObjects)
5886973a582SRatan Gupta                     {
58954fc587aSNagaraju Goruganti                         // let's find the object whose ldap type is equal to the
59054fc587aSNagaraju Goruganti                         // given type
591bd79bce8SPatrick Williams                         if (object.first.str.find(searchString) ==
592bd79bce8SPatrick Williams                             std::string::npos)
5936973a582SRatan Gupta                         {
594ab828d7cSRatan Gupta                             continue;
595ab828d7cSRatan Gupta                         }
596ab828d7cSRatan Gupta 
5976973a582SRatan Gupta                         for (const auto& interface : object.second)
5986973a582SRatan Gupta                         {
5996973a582SRatan Gupta                             if (interface.first == ldapEnableInterfaceStr)
6006973a582SRatan Gupta                             {
6016973a582SRatan Gupta                                 // rest of the properties are string.
6026973a582SRatan Gupta                                 for (const auto& property : interface.second)
6036973a582SRatan Gupta                                 {
6046973a582SRatan Gupta                                     if (property.first == "Enabled")
6056973a582SRatan Gupta                                     {
6066973a582SRatan Gupta                                         const bool* value =
6076973a582SRatan Gupta                                             std::get_if<bool>(&property.second);
6086973a582SRatan Gupta                                         if (value == nullptr)
6096973a582SRatan Gupta                                         {
6106973a582SRatan Gupta                                             continue;
6116973a582SRatan Gupta                                         }
6126973a582SRatan Gupta                                         confData.serviceEnabled = *value;
6136973a582SRatan Gupta                                         break;
6146973a582SRatan Gupta                                     }
6156973a582SRatan Gupta                                 }
6166973a582SRatan Gupta                             }
6176973a582SRatan Gupta                             else if (interface.first == ldapConfigInterfaceStr)
6186973a582SRatan Gupta                             {
6196973a582SRatan Gupta                                 for (const auto& property : interface.second)
6206973a582SRatan Gupta                                 {
621271584abSEd Tanous                                     const std::string* strValue =
622bd79bce8SPatrick Williams                                         std::get_if<std::string>(
623bd79bce8SPatrick Williams                                             &property.second);
624271584abSEd Tanous                                     if (strValue == nullptr)
6256973a582SRatan Gupta                                     {
6266973a582SRatan Gupta                                         continue;
6276973a582SRatan Gupta                                     }
6286973a582SRatan Gupta                                     if (property.first == "LDAPServerURI")
6296973a582SRatan Gupta                                     {
630271584abSEd Tanous                                         confData.uri = *strValue;
6316973a582SRatan Gupta                                     }
6326973a582SRatan Gupta                                     else if (property.first == "LDAPBindDN")
6336973a582SRatan Gupta                                     {
634271584abSEd Tanous                                         confData.bindDN = *strValue;
6356973a582SRatan Gupta                                     }
6366973a582SRatan Gupta                                     else if (property.first == "LDAPBaseDN")
6376973a582SRatan Gupta                                     {
638271584abSEd Tanous                                         confData.baseDN = *strValue;
6396973a582SRatan Gupta                                     }
640bd79bce8SPatrick Williams                                     else if (property.first ==
641bd79bce8SPatrick Williams                                              "LDAPSearchScope")
6426973a582SRatan Gupta                                     {
643271584abSEd Tanous                                         confData.searchScope = *strValue;
6446973a582SRatan Gupta                                     }
645bd79bce8SPatrick Williams                                     else if (property.first ==
646bd79bce8SPatrick Williams                                              "GroupNameAttribute")
6476973a582SRatan Gupta                                     {
648271584abSEd Tanous                                         confData.groupAttribute = *strValue;
6496973a582SRatan Gupta                                     }
650bd79bce8SPatrick Williams                                     else if (property.first ==
651bd79bce8SPatrick Williams                                              "UserNameAttribute")
6526973a582SRatan Gupta                                     {
653271584abSEd Tanous                                         confData.userNameAttribute = *strValue;
6546973a582SRatan Gupta                                     }
65554fc587aSNagaraju Goruganti                                     else if (property.first == "LDAPType")
656ab828d7cSRatan Gupta                                     {
657271584abSEd Tanous                                         confData.serverType = *strValue;
65854fc587aSNagaraju Goruganti                                     }
65954fc587aSNagaraju Goruganti                                 }
66054fc587aSNagaraju Goruganti                             }
661bd79bce8SPatrick Williams                             else if (
662bd79bce8SPatrick Williams                                 interface.first ==
6630fda0f12SGeorge Liu                                 "xyz.openbmc_project.User.PrivilegeMapperEntry")
66454fc587aSNagaraju Goruganti                             {
66554fc587aSNagaraju Goruganti                                 LDAPRoleMapData roleMapData{};
66654fc587aSNagaraju Goruganti                                 for (const auto& property : interface.second)
66754fc587aSNagaraju Goruganti                                 {
668271584abSEd Tanous                                     const std::string* strValue =
669bd79bce8SPatrick Williams                                         std::get_if<std::string>(
670bd79bce8SPatrick Williams                                             &property.second);
67154fc587aSNagaraju Goruganti 
672271584abSEd Tanous                                     if (strValue == nullptr)
67354fc587aSNagaraju Goruganti                                     {
67454fc587aSNagaraju Goruganti                                         continue;
67554fc587aSNagaraju Goruganti                                     }
67654fc587aSNagaraju Goruganti 
67754fc587aSNagaraju Goruganti                                     if (property.first == "GroupName")
67854fc587aSNagaraju Goruganti                                     {
679271584abSEd Tanous                                         roleMapData.groupName = *strValue;
68054fc587aSNagaraju Goruganti                                     }
68154fc587aSNagaraju Goruganti                                     else if (property.first == "Privilege")
68254fc587aSNagaraju Goruganti                                     {
683271584abSEd Tanous                                         roleMapData.privilege = *strValue;
68454fc587aSNagaraju Goruganti                                     }
68554fc587aSNagaraju Goruganti                                 }
68654fc587aSNagaraju Goruganti 
687bd79bce8SPatrick Williams                                 confData.groupRoleList.emplace_back(
688bd79bce8SPatrick Williams                                     object.first.str, roleMapData);
68954fc587aSNagaraju Goruganti                             }
69054fc587aSNagaraju Goruganti                         }
69154fc587aSNagaraju Goruganti                     }
692ab828d7cSRatan Gupta                     callback(true, confData, ldapType);
6935eb468daSGeorge Liu                 });
6942b73119cSGeorge Liu         });
6956973a582SRatan Gupta }
6966973a582SRatan Gupta 
6978a07d286SRatan Gupta /**
6988a07d286SRatan Gupta  * @brief updates the LDAP server address and updates the
6998a07d286SRatan Gupta           json response with the new value.
7008a07d286SRatan Gupta  * @param serviceAddressList address to be updated.
7018a07d286SRatan Gupta  * @param asyncResp pointer to the JSON response
7028a07d286SRatan Gupta  * @param ldapServerElementName Type of LDAP
7038a07d286SRatan Gupta  server(openLDAP/ActiveDirectory)
7048a07d286SRatan Gupta  */
7058a07d286SRatan Gupta 
7064f48d5f6SEd Tanous inline void handleServiceAddressPatch(
7078a07d286SRatan Gupta     const std::vector<std::string>& serviceAddressList,
7088d1b46d7Szhanghch05     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
7098a07d286SRatan Gupta     const std::string& ldapServerElementName,
7108a07d286SRatan Gupta     const std::string& ldapConfigObject)
7118a07d286SRatan Gupta {
712e93abac6SGinu George     setDbusProperty(asyncResp, ldapServerElementName + "/ServiceAddress",
713e93abac6SGinu George                     ldapDbusService, ldapConfigObject, ldapConfigInterface,
714e93abac6SGinu George                     "LDAPServerURI", serviceAddressList.front());
7158a07d286SRatan Gupta }
7168a07d286SRatan Gupta /**
7178a07d286SRatan Gupta  * @brief updates the LDAP Bind DN and updates the
7188a07d286SRatan Gupta           json response with the new value.
7198a07d286SRatan Gupta  * @param username name of the user which needs to be updated.
7208a07d286SRatan Gupta  * @param asyncResp pointer to the JSON response
7218a07d286SRatan Gupta  * @param ldapServerElementName Type of LDAP
7228a07d286SRatan Gupta  server(openLDAP/ActiveDirectory)
7238a07d286SRatan Gupta  */
7248a07d286SRatan Gupta 
7254f48d5f6SEd Tanous inline void
7264f48d5f6SEd Tanous     handleUserNamePatch(const std::string& username,
7278d1b46d7Szhanghch05                         const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
7288a07d286SRatan Gupta                         const std::string& ldapServerElementName,
7298a07d286SRatan Gupta                         const std::string& ldapConfigObject)
7308a07d286SRatan Gupta {
731e93abac6SGinu George     setDbusProperty(asyncResp,
732d02aad39SEd Tanous                     ldapServerElementName + "/Authentication/Username",
733e93abac6SGinu George                     ldapDbusService, ldapConfigObject, ldapConfigInterface,
734e93abac6SGinu George                     "LDAPBindDN", username);
7358a07d286SRatan Gupta }
7368a07d286SRatan Gupta 
7378a07d286SRatan Gupta /**
7388a07d286SRatan Gupta  * @brief updates the LDAP password
7398a07d286SRatan Gupta  * @param password : ldap password which needs to be updated.
7408a07d286SRatan Gupta  * @param asyncResp pointer to the JSON response
7418a07d286SRatan Gupta  * @param ldapServerElementName Type of LDAP
7428a07d286SRatan Gupta  *        server(openLDAP/ActiveDirectory)
7438a07d286SRatan Gupta  */
7448a07d286SRatan Gupta 
7454f48d5f6SEd Tanous inline void
7464f48d5f6SEd Tanous     handlePasswordPatch(const std::string& password,
7478d1b46d7Szhanghch05                         const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
7488a07d286SRatan Gupta                         const std::string& ldapServerElementName,
7498a07d286SRatan Gupta                         const std::string& ldapConfigObject)
7508a07d286SRatan Gupta {
751e93abac6SGinu George     setDbusProperty(asyncResp,
752d02aad39SEd Tanous                     ldapServerElementName + "/Authentication/Password",
753e93abac6SGinu George                     ldapDbusService, ldapConfigObject, ldapConfigInterface,
754e93abac6SGinu George                     "LDAPBindDNPassword", password);
7558a07d286SRatan Gupta }
7568a07d286SRatan Gupta 
7578a07d286SRatan Gupta /**
7588a07d286SRatan Gupta  * @brief updates the LDAP BaseDN and updates the
7598a07d286SRatan Gupta           json response with the new value.
7608a07d286SRatan Gupta  * @param baseDNList baseDN list which needs to be updated.
7618a07d286SRatan Gupta  * @param asyncResp pointer to the JSON response
7628a07d286SRatan Gupta  * @param ldapServerElementName Type of LDAP
7638a07d286SRatan Gupta  server(openLDAP/ActiveDirectory)
7648a07d286SRatan Gupta  */
7658a07d286SRatan Gupta 
7664f48d5f6SEd Tanous inline void
7674f48d5f6SEd Tanous     handleBaseDNPatch(const std::vector<std::string>& baseDNList,
7688d1b46d7Szhanghch05                       const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
7698a07d286SRatan Gupta                       const std::string& ldapServerElementName,
7708a07d286SRatan Gupta                       const std::string& ldapConfigObject)
7718a07d286SRatan Gupta {
772e93abac6SGinu George     setDbusProperty(asyncResp,
773d02aad39SEd Tanous                     ldapServerElementName +
774d02aad39SEd Tanous                         "/LDAPService/SearchSettings/BaseDistinguishedNames",
775e93abac6SGinu George                     ldapDbusService, ldapConfigObject, ldapConfigInterface,
776e93abac6SGinu George                     "LDAPBaseDN", baseDNList.front());
7778a07d286SRatan Gupta }
7788a07d286SRatan Gupta /**
7798a07d286SRatan Gupta  * @brief updates the LDAP user name attribute and updates the
7808a07d286SRatan Gupta           json response with the new value.
7818a07d286SRatan Gupta  * @param userNameAttribute attribute to be updated.
7828a07d286SRatan Gupta  * @param asyncResp pointer to the JSON response
7838a07d286SRatan Gupta  * @param ldapServerElementName Type of LDAP
7848a07d286SRatan Gupta  server(openLDAP/ActiveDirectory)
7858a07d286SRatan Gupta  */
7868a07d286SRatan Gupta 
787bd79bce8SPatrick Williams inline void handleUserNameAttrPatch(
788bd79bce8SPatrick Williams     const std::string& userNameAttribute,
7898d1b46d7Szhanghch05     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
7908a07d286SRatan Gupta     const std::string& ldapServerElementName,
7918a07d286SRatan Gupta     const std::string& ldapConfigObject)
7928a07d286SRatan Gupta {
793bd79bce8SPatrick Williams     setDbusProperty(
794bd79bce8SPatrick Williams         asyncResp,
795bd79bce8SPatrick Williams         ldapServerElementName + "LDAPService/SearchSettings/UsernameAttribute",
796e93abac6SGinu George         ldapDbusService, ldapConfigObject, ldapConfigInterface,
797e93abac6SGinu George         "UserNameAttribute", userNameAttribute);
7988a07d286SRatan Gupta }
7998a07d286SRatan Gupta /**
8008a07d286SRatan Gupta  * @brief updates the LDAP group attribute and updates the
8018a07d286SRatan Gupta           json response with the new value.
8028a07d286SRatan Gupta  * @param groupsAttribute attribute to be updated.
8038a07d286SRatan Gupta  * @param asyncResp pointer to the JSON response
8048a07d286SRatan Gupta  * @param ldapServerElementName Type of LDAP
8058a07d286SRatan Gupta  server(openLDAP/ActiveDirectory)
8068a07d286SRatan Gupta  */
8078a07d286SRatan Gupta 
8084f48d5f6SEd Tanous inline void handleGroupNameAttrPatch(
8098d1b46d7Szhanghch05     const std::string& groupsAttribute,
8108d1b46d7Szhanghch05     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
8118a07d286SRatan Gupta     const std::string& ldapServerElementName,
8128a07d286SRatan Gupta     const std::string& ldapConfigObject)
8138a07d286SRatan Gupta {
814bd79bce8SPatrick Williams     setDbusProperty(
815bd79bce8SPatrick Williams         asyncResp,
816bd79bce8SPatrick Williams         ldapServerElementName + "/LDAPService/SearchSettings/GroupsAttribute",
817e93abac6SGinu George         ldapDbusService, ldapConfigObject, ldapConfigInterface,
818e93abac6SGinu George         "GroupNameAttribute", groupsAttribute);
8198a07d286SRatan Gupta }
8208a07d286SRatan Gupta /**
8218a07d286SRatan Gupta  * @brief updates the LDAP service enable and updates the
8228a07d286SRatan Gupta           json response with the new value.
8238a07d286SRatan Gupta  * @param input JSON data.
8248a07d286SRatan Gupta  * @param asyncResp pointer to the JSON response
8258a07d286SRatan Gupta  * @param ldapServerElementName Type of LDAP
8268a07d286SRatan Gupta  server(openLDAP/ActiveDirectory)
8278a07d286SRatan Gupta  */
8288a07d286SRatan Gupta 
8294f48d5f6SEd Tanous inline void handleServiceEnablePatch(
8306c51eab1SEd Tanous     bool serviceEnabled, const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
8318a07d286SRatan Gupta     const std::string& ldapServerElementName,
8328a07d286SRatan Gupta     const std::string& ldapConfigObject)
8338a07d286SRatan Gupta {
834e93abac6SGinu George     setDbusProperty(asyncResp, ldapServerElementName + "/ServiceEnabled",
835e93abac6SGinu George                     ldapDbusService, ldapConfigObject, ldapEnableInterface,
836e93abac6SGinu George                     "Enabled", serviceEnabled);
8378a07d286SRatan Gupta }
8388a07d286SRatan Gupta 
839c1019828SEd Tanous struct AuthMethods
84078158631SZbigniew Kurzynski {
84178158631SZbigniew Kurzynski     std::optional<bool> basicAuth;
84278158631SZbigniew Kurzynski     std::optional<bool> cookie;
84378158631SZbigniew Kurzynski     std::optional<bool> sessionToken;
84478158631SZbigniew Kurzynski     std::optional<bool> xToken;
845501f1e58SZbigniew Kurzynski     std::optional<bool> tls;
846c1019828SEd Tanous };
84778158631SZbigniew Kurzynski 
848c1019828SEd Tanous inline void
849c1019828SEd Tanous     handleAuthMethodsPatch(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
850c1019828SEd Tanous                            const AuthMethods& auth)
85178158631SZbigniew Kurzynski {
852c1019828SEd Tanous     persistent_data::AuthConfigMethods& authMethodsConfig =
85352cc112dSEd Tanous         persistent_data::SessionStore::getInstance().getAuthMethodsConfig();
85478158631SZbigniew Kurzynski 
855c1019828SEd Tanous     if (auth.basicAuth)
85678158631SZbigniew Kurzynski     {
85725b54dbaSEd Tanous         if constexpr (!BMCWEB_BASIC_AUTH)
85825b54dbaSEd Tanous         {
859f16f6263SAlan Kuo             messages::actionNotSupported(
8600fda0f12SGeorge Liu                 asyncResp->res,
8610fda0f12SGeorge Liu                 "Setting BasicAuth when basic-auth feature is disabled");
862f16f6263SAlan Kuo             return;
86325b54dbaSEd Tanous         }
86425b54dbaSEd Tanous 
865c1019828SEd Tanous         authMethodsConfig.basic = *auth.basicAuth;
86678158631SZbigniew Kurzynski     }
86778158631SZbigniew Kurzynski 
868c1019828SEd Tanous     if (auth.cookie)
86978158631SZbigniew Kurzynski     {
87025b54dbaSEd Tanous         if constexpr (!BMCWEB_COOKIE_AUTH)
87125b54dbaSEd Tanous         {
8720fda0f12SGeorge Liu             messages::actionNotSupported(
8730fda0f12SGeorge Liu                 asyncResp->res,
8740fda0f12SGeorge Liu                 "Setting Cookie when cookie-auth feature is disabled");
875f16f6263SAlan Kuo             return;
87625b54dbaSEd Tanous         }
877c1019828SEd Tanous         authMethodsConfig.cookie = *auth.cookie;
87878158631SZbigniew Kurzynski     }
87978158631SZbigniew Kurzynski 
880c1019828SEd Tanous     if (auth.sessionToken)
88178158631SZbigniew Kurzynski     {
88225b54dbaSEd Tanous         if constexpr (!BMCWEB_SESSION_AUTH)
88325b54dbaSEd Tanous         {
884f16f6263SAlan Kuo             messages::actionNotSupported(
8850fda0f12SGeorge Liu                 asyncResp->res,
8860fda0f12SGeorge Liu                 "Setting SessionToken when session-auth feature is disabled");
887f16f6263SAlan Kuo             return;
88825b54dbaSEd Tanous         }
889c1019828SEd Tanous         authMethodsConfig.sessionToken = *auth.sessionToken;
89078158631SZbigniew Kurzynski     }
89178158631SZbigniew Kurzynski 
892c1019828SEd Tanous     if (auth.xToken)
89378158631SZbigniew Kurzynski     {
89425b54dbaSEd Tanous         if constexpr (!BMCWEB_XTOKEN_AUTH)
89525b54dbaSEd Tanous         {
8960fda0f12SGeorge Liu             messages::actionNotSupported(
8970fda0f12SGeorge Liu                 asyncResp->res,
8980fda0f12SGeorge Liu                 "Setting XToken when xtoken-auth feature is disabled");
899f16f6263SAlan Kuo             return;
90025b54dbaSEd Tanous         }
901c1019828SEd Tanous         authMethodsConfig.xtoken = *auth.xToken;
90278158631SZbigniew Kurzynski     }
90378158631SZbigniew Kurzynski 
904c1019828SEd Tanous     if (auth.tls)
905501f1e58SZbigniew Kurzynski     {
90625b54dbaSEd Tanous         if constexpr (!BMCWEB_MUTUAL_TLS_AUTH)
90725b54dbaSEd Tanous         {
9080fda0f12SGeorge Liu             messages::actionNotSupported(
9090fda0f12SGeorge Liu                 asyncResp->res,
9100fda0f12SGeorge Liu                 "Setting TLS when mutual-tls-auth feature is disabled");
911f16f6263SAlan Kuo             return;
91225b54dbaSEd Tanous         }
913c1019828SEd Tanous         authMethodsConfig.tls = *auth.tls;
914501f1e58SZbigniew Kurzynski     }
915501f1e58SZbigniew Kurzynski 
91678158631SZbigniew Kurzynski     if (!authMethodsConfig.basic && !authMethodsConfig.cookie &&
917501f1e58SZbigniew Kurzynski         !authMethodsConfig.sessionToken && !authMethodsConfig.xtoken &&
918501f1e58SZbigniew Kurzynski         !authMethodsConfig.tls)
91978158631SZbigniew Kurzynski     {
92078158631SZbigniew Kurzynski         // Do not allow user to disable everything
92178158631SZbigniew Kurzynski         messages::actionNotSupported(asyncResp->res,
92278158631SZbigniew Kurzynski                                      "of disabling all available methods");
92378158631SZbigniew Kurzynski         return;
92478158631SZbigniew Kurzynski     }
92578158631SZbigniew Kurzynski 
92652cc112dSEd Tanous     persistent_data::SessionStore::getInstance().updateAuthMethodsConfig(
92752cc112dSEd Tanous         authMethodsConfig);
92878158631SZbigniew Kurzynski     // Save configuration immediately
92952cc112dSEd Tanous     persistent_data::getConfig().writeData();
93078158631SZbigniew Kurzynski 
93178158631SZbigniew Kurzynski     messages::success(asyncResp->res);
93278158631SZbigniew Kurzynski }
93378158631SZbigniew Kurzynski 
9348a07d286SRatan Gupta /**
9358a07d286SRatan Gupta  * @brief Get the required values from the given JSON, validates the
9368a07d286SRatan Gupta  *        value and create the LDAP config object.
9378a07d286SRatan Gupta  * @param input JSON data
9388a07d286SRatan Gupta  * @param asyncResp pointer to the JSON response
9398a07d286SRatan Gupta  * @param serverType Type of LDAP server(openLDAP/ActiveDirectory)
9408a07d286SRatan Gupta  */
9418a07d286SRatan Gupta 
94210cb44f3SEd Tanous struct LdapPatchParams
94310cb44f3SEd Tanous {
94410cb44f3SEd Tanous     std::optional<std::string> authType;
94510cb44f3SEd Tanous     std::optional<std::vector<std::string>> serviceAddressList;
94610cb44f3SEd Tanous     std::optional<bool> serviceEnabled;
94710cb44f3SEd Tanous     std::optional<std::vector<std::string>> baseDNList;
94810cb44f3SEd Tanous     std::optional<std::string> userNameAttribute;
94910cb44f3SEd Tanous     std::optional<std::string> groupsAttribute;
95010cb44f3SEd Tanous     std::optional<std::string> userName;
95110cb44f3SEd Tanous     std::optional<std::string> password;
95210cb44f3SEd Tanous     std::optional<
95310cb44f3SEd Tanous         std::vector<std::variant<nlohmann::json::object_t, std::nullptr_t>>>
95410cb44f3SEd Tanous         remoteRoleMapData;
95510cb44f3SEd Tanous };
95610cb44f3SEd Tanous 
95710cb44f3SEd Tanous inline void handleLDAPPatch(LdapPatchParams&& input,
9588d1b46d7Szhanghch05                             const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
9598a07d286SRatan Gupta                             const std::string& serverType)
9608a07d286SRatan Gupta {
961eb2bbe56SRatan Gupta     std::string dbusObjectPath;
962eb2bbe56SRatan Gupta     if (serverType == "ActiveDirectory")
963eb2bbe56SRatan Gupta     {
9642c70f800SEd Tanous         dbusObjectPath = adConfigObject;
965eb2bbe56SRatan Gupta     }
966eb2bbe56SRatan Gupta     else if (serverType == "LDAP")
967eb2bbe56SRatan Gupta     {
96823a21a1cSEd Tanous         dbusObjectPath = ldapConfigObjectName;
969eb2bbe56SRatan Gupta     }
970cb13a392SEd Tanous     else
971cb13a392SEd Tanous     {
97210cb44f3SEd Tanous         BMCWEB_LOG_ERROR("serverType wasn't AD or LDAP but was {}????",
97310cb44f3SEd Tanous                          serverType);
974cb13a392SEd Tanous         return;
975cb13a392SEd Tanous     }
976eb2bbe56SRatan Gupta 
97710cb44f3SEd Tanous     if (input.authType && *input.authType != "UsernameAndPassword")
9788a07d286SRatan Gupta     {
97910cb44f3SEd Tanous         messages::propertyValueNotInList(asyncResp->res, *input.authType,
980c1019828SEd Tanous                                          "AuthenticationType");
981c1019828SEd Tanous         return;
9828a07d286SRatan Gupta     }
983c1019828SEd Tanous 
98410cb44f3SEd Tanous     if (input.serviceAddressList)
9858a07d286SRatan Gupta     {
98610cb44f3SEd Tanous         if (input.serviceAddressList->empty())
9878a07d286SRatan Gupta         {
988e2616cc5SEd Tanous             messages::propertyValueNotInList(
98910cb44f3SEd Tanous                 asyncResp->res, *input.serviceAddressList, "ServiceAddress");
9908a07d286SRatan Gupta             return;
9918a07d286SRatan Gupta         }
9928a07d286SRatan Gupta     }
99310cb44f3SEd Tanous     if (input.baseDNList)
9948a07d286SRatan Gupta     {
99510cb44f3SEd Tanous         if (input.baseDNList->empty())
9968a07d286SRatan Gupta         {
99710cb44f3SEd Tanous             messages::propertyValueNotInList(asyncResp->res, *input.baseDNList,
9988a07d286SRatan Gupta                                              "BaseDistinguishedNames");
9998a07d286SRatan Gupta             return;
10008a07d286SRatan Gupta         }
10018a07d286SRatan Gupta     }
10028a07d286SRatan Gupta 
10038a07d286SRatan Gupta     // nothing to update, then return
100410cb44f3SEd Tanous     if (!input.userName && !input.password && !input.serviceAddressList &&
100510cb44f3SEd Tanous         !input.baseDNList && !input.userNameAttribute &&
100610cb44f3SEd Tanous         !input.groupsAttribute && !input.serviceEnabled &&
100710cb44f3SEd Tanous         !input.remoteRoleMapData)
10088a07d286SRatan Gupta     {
10098a07d286SRatan Gupta         return;
10108a07d286SRatan Gupta     }
10118a07d286SRatan Gupta 
10128a07d286SRatan Gupta     // Get the existing resource first then keep modifying
10138a07d286SRatan Gupta     // whenever any property gets updated.
1014bd79bce8SPatrick Williams     getLDAPConfigData(serverType, [asyncResp, input = std::move(input),
101510cb44f3SEd Tanous                                    dbusObjectPath = std::move(dbusObjectPath)](
1016bd79bce8SPatrick Williams                                       bool success,
1017bd79bce8SPatrick Williams                                       const LDAPConfigData& confData,
1018c1019828SEd Tanous                                       const std::string& serverT) mutable {
10198a07d286SRatan Gupta         if (!success)
10208a07d286SRatan Gupta         {
10218a07d286SRatan Gupta             messages::internalError(asyncResp->res);
10228a07d286SRatan Gupta             return;
10238a07d286SRatan Gupta         }
10246c51eab1SEd Tanous         parseLDAPConfigData(asyncResp->res.jsonValue, confData, serverT);
10258a07d286SRatan Gupta         if (confData.serviceEnabled)
10268a07d286SRatan Gupta         {
10278a07d286SRatan Gupta             // Disable the service first and update the rest of
10288a07d286SRatan Gupta             // the properties.
10296c51eab1SEd Tanous             handleServiceEnablePatch(false, asyncResp, serverT, dbusObjectPath);
10308a07d286SRatan Gupta         }
10318a07d286SRatan Gupta 
103210cb44f3SEd Tanous         if (input.serviceAddressList)
10338a07d286SRatan Gupta         {
103410cb44f3SEd Tanous             handleServiceAddressPatch(*input.serviceAddressList, asyncResp,
103510cb44f3SEd Tanous                                       serverT, dbusObjectPath);
103610cb44f3SEd Tanous         }
103710cb44f3SEd Tanous         if (input.userName)
103810cb44f3SEd Tanous         {
103910cb44f3SEd Tanous             handleUserNamePatch(*input.userName, asyncResp, serverT,
10406c51eab1SEd Tanous                                 dbusObjectPath);
10418a07d286SRatan Gupta         }
104210cb44f3SEd Tanous         if (input.password)
10438a07d286SRatan Gupta         {
104410cb44f3SEd Tanous             handlePasswordPatch(*input.password, asyncResp, serverT,
104510cb44f3SEd Tanous                                 dbusObjectPath);
10468a07d286SRatan Gupta         }
10478a07d286SRatan Gupta 
104810cb44f3SEd Tanous         if (input.baseDNList)
10498a07d286SRatan Gupta         {
105010cb44f3SEd Tanous             handleBaseDNPatch(*input.baseDNList, asyncResp, serverT,
10516c51eab1SEd Tanous                               dbusObjectPath);
10528a07d286SRatan Gupta         }
105310cb44f3SEd Tanous         if (input.userNameAttribute)
10548a07d286SRatan Gupta         {
105510cb44f3SEd Tanous             handleUserNameAttrPatch(*input.userNameAttribute, asyncResp,
105610cb44f3SEd Tanous                                     serverT, dbusObjectPath);
105710cb44f3SEd Tanous         }
105810cb44f3SEd Tanous         if (input.groupsAttribute)
105910cb44f3SEd Tanous         {
106010cb44f3SEd Tanous             handleGroupNameAttrPatch(*input.groupsAttribute, asyncResp, serverT,
10616c51eab1SEd Tanous                                      dbusObjectPath);
10628a07d286SRatan Gupta         }
106310cb44f3SEd Tanous         if (input.serviceEnabled)
10648a07d286SRatan Gupta         {
10658a07d286SRatan Gupta             // if user has given the value as true then enable
10668a07d286SRatan Gupta             // the service. if user has given false then no-op
10678a07d286SRatan Gupta             // as service is already stopped.
106810cb44f3SEd Tanous             if (*input.serviceEnabled)
10698a07d286SRatan Gupta             {
107010cb44f3SEd Tanous                 handleServiceEnablePatch(*input.serviceEnabled, asyncResp,
107110cb44f3SEd Tanous                                          serverT, dbusObjectPath);
10728a07d286SRatan Gupta             }
10738a07d286SRatan Gupta         }
10748a07d286SRatan Gupta         else
10758a07d286SRatan Gupta         {
10768a07d286SRatan Gupta             // if user has not given the service enabled value
10778a07d286SRatan Gupta             // then revert it to the same state as it was
10788a07d286SRatan Gupta             // before.
10798a07d286SRatan Gupta             handleServiceEnablePatch(confData.serviceEnabled, asyncResp,
108023a21a1cSEd Tanous                                      serverT, dbusObjectPath);
10818a07d286SRatan Gupta         }
108206785244SRatan Gupta 
108310cb44f3SEd Tanous         if (input.remoteRoleMapData)
108406785244SRatan Gupta         {
10856c51eab1SEd Tanous             handleRoleMapPatch(asyncResp, confData.groupRoleList, serverT,
108610cb44f3SEd Tanous                                *input.remoteRoleMapData);
108706785244SRatan Gupta         }
10888a07d286SRatan Gupta     });
10898a07d286SRatan Gupta }
1090d4b5443fSEd Tanous 
109158345856SAbhishek Patel inline void updateUserProperties(
109258345856SAbhishek Patel     std::shared_ptr<bmcweb::AsyncResp> asyncResp, const std::string& username,
1093618c14b4SEd Tanous     const std::optional<std::string>& password,
1094618c14b4SEd Tanous     const std::optional<bool>& enabled,
109558345856SAbhishek Patel     const std::optional<std::string>& roleId, const std::optional<bool>& locked,
1096e518ef32SRavi Teja     std::optional<std::vector<std::string>> accountTypes, bool userSelf,
1097e518ef32SRavi Teja     const std::shared_ptr<persistent_data::UserSession>& session)
10981abe55efSEd Tanous {
1099b477fd44SP Dheeraj Srujan Kumar     sdbusplus::message::object_path tempObjPath(rootUserDbusPath);
1100b477fd44SP Dheeraj Srujan Kumar     tempObjPath /= username;
1101b477fd44SP Dheeraj Srujan Kumar     std::string dbusObjectPath(tempObjPath);
11026c51eab1SEd Tanous 
11036c51eab1SEd Tanous     dbus::utility::checkDbusPathExists(
1104e518ef32SRavi Teja         dbusObjectPath,
1105e518ef32SRavi Teja         [dbusObjectPath, username, password, roleId, enabled, locked,
1106e518ef32SRavi Teja          accountTypes(std::move(accountTypes)), userSelf, session,
1107e518ef32SRavi Teja          asyncResp{std::move(asyncResp)}](int rc) {
1108e662eae8SEd Tanous             if (rc <= 0)
11096c51eab1SEd Tanous             {
1110d8a5d5d8SJiaqing Zhao                 messages::resourceNotFound(asyncResp->res, "ManagerAccount",
11116c51eab1SEd Tanous                                            username);
11126c51eab1SEd Tanous                 return;
11136c51eab1SEd Tanous             }
11146c51eab1SEd Tanous 
11156c51eab1SEd Tanous             if (password)
11166c51eab1SEd Tanous             {
11176c51eab1SEd Tanous                 int retval = pamUpdatePassword(username, *password);
11186c51eab1SEd Tanous 
11196c51eab1SEd Tanous                 if (retval == PAM_USER_UNKNOWN)
11206c51eab1SEd Tanous                 {
1121d8a5d5d8SJiaqing Zhao                     messages::resourceNotFound(asyncResp->res, "ManagerAccount",
11226c51eab1SEd Tanous                                                username);
11236c51eab1SEd Tanous                 }
11246c51eab1SEd Tanous                 else if (retval == PAM_AUTHTOK_ERR)
11256c51eab1SEd Tanous                 {
11266c51eab1SEd Tanous                     // If password is invalid
11279bd80831SJason M. Bills                     messages::propertyValueFormatError(asyncResp->res, nullptr,
11289bd80831SJason M. Bills                                                        "Password");
112962598e31SEd Tanous                     BMCWEB_LOG_ERROR("pamUpdatePassword Failed");
11306c51eab1SEd Tanous                 }
11316c51eab1SEd Tanous                 else if (retval != PAM_SUCCESS)
11326c51eab1SEd Tanous                 {
11336c51eab1SEd Tanous                     messages::internalError(asyncResp->res);
11346c51eab1SEd Tanous                     return;
11356c51eab1SEd Tanous                 }
1136e7b1b62bSEd Tanous                 else
1137e7b1b62bSEd Tanous                 {
1138bd79bce8SPatrick Williams                     // Remove existing sessions of the user when password
1139bd79bce8SPatrick Williams                     // changed
1140e518ef32SRavi Teja                     persistent_data::SessionStore::getInstance()
1141bd79bce8SPatrick Williams                         .removeSessionsByUsernameExceptSession(username,
1142bd79bce8SPatrick Williams                                                                session);
1143e7b1b62bSEd Tanous                     messages::success(asyncResp->res);
1144e7b1b62bSEd Tanous                 }
11456c51eab1SEd Tanous             }
11466c51eab1SEd Tanous 
11476c51eab1SEd Tanous             if (enabled)
11486c51eab1SEd Tanous             {
1149bd79bce8SPatrick Williams                 setDbusProperty(
1150bd79bce8SPatrick Williams                     asyncResp, "Enabled", "xyz.openbmc_project.User.Manager",
1151bd79bce8SPatrick Williams                     dbusObjectPath, "xyz.openbmc_project.User.Attributes",
1152e93abac6SGinu George                     "UserEnabled", *enabled);
11536c51eab1SEd Tanous             }
11546c51eab1SEd Tanous 
11556c51eab1SEd Tanous             if (roleId)
11566c51eab1SEd Tanous             {
11576c51eab1SEd Tanous                 std::string priv = getPrivilegeFromRoleId(*roleId);
11586c51eab1SEd Tanous                 if (priv.empty())
11596c51eab1SEd Tanous                 {
1160e2616cc5SEd Tanous                     messages::propertyValueNotInList(asyncResp->res, true,
1161e2616cc5SEd Tanous                                                      "Locked");
11626c51eab1SEd Tanous                     return;
11636c51eab1SEd Tanous                 }
1164bd79bce8SPatrick Williams                 setDbusProperty(
1165bd79bce8SPatrick Williams                     asyncResp, "RoleId", "xyz.openbmc_project.User.Manager",
1166bd79bce8SPatrick Williams                     dbusObjectPath, "xyz.openbmc_project.User.Attributes",
1167e93abac6SGinu George                     "UserPrivilege", priv);
11686c51eab1SEd Tanous             }
11696c51eab1SEd Tanous 
11706c51eab1SEd Tanous             if (locked)
11716c51eab1SEd Tanous             {
11726c51eab1SEd Tanous                 // admin can unlock the account which is locked by
11736c51eab1SEd Tanous                 // successive authentication failures but admin should
11746c51eab1SEd Tanous                 // not be allowed to lock an account.
11756c51eab1SEd Tanous                 if (*locked)
11766c51eab1SEd Tanous                 {
11776c51eab1SEd Tanous                     messages::propertyValueNotInList(asyncResp->res, "true",
11786c51eab1SEd Tanous                                                      "Locked");
11796c51eab1SEd Tanous                     return;
11806c51eab1SEd Tanous                 }
1181bd79bce8SPatrick Williams                 setDbusProperty(
1182bd79bce8SPatrick Williams                     asyncResp, "Locked", "xyz.openbmc_project.User.Manager",
1183bd79bce8SPatrick Williams                     dbusObjectPath, "xyz.openbmc_project.User.Attributes",
1184e93abac6SGinu George                     "UserLockedForFailedAttempt", *locked);
11856c51eab1SEd Tanous             }
118658345856SAbhishek Patel 
118758345856SAbhishek Patel             if (accountTypes)
118858345856SAbhishek Patel             {
118958345856SAbhishek Patel                 patchAccountTypes(*accountTypes, asyncResp, dbusObjectPath,
119058345856SAbhishek Patel                                   userSelf);
119158345856SAbhishek Patel             }
11926c51eab1SEd Tanous         });
11936c51eab1SEd Tanous }
11946c51eab1SEd Tanous 
11954c7d4d33SEd Tanous inline void handleAccountServiceHead(
11964c7d4d33SEd Tanous     App& app, const crow::Request& req,
11971ef4c342SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
11986c51eab1SEd Tanous {
11993ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
120045ca1b86SEd Tanous     {
120145ca1b86SEd Tanous         return;
120245ca1b86SEd Tanous     }
12034c7d4d33SEd Tanous     asyncResp->res.addHeader(
12044c7d4d33SEd Tanous         boost::beast::http::field::link,
12054c7d4d33SEd Tanous         "</redfish/v1/JsonSchemas/AccountService/AccountService.json>; rel=describedby");
12064c7d4d33SEd Tanous }
12074c7d4d33SEd Tanous 
12084c7d4d33SEd Tanous inline void
12091aa375b8SEd Tanous     getClientCertificates(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
12101aa375b8SEd Tanous                           const nlohmann::json::json_pointer& keyLocation)
12111aa375b8SEd Tanous {
12121aa375b8SEd Tanous     boost::urls::url url(
12131aa375b8SEd Tanous         "/redfish/v1/AccountService/MultiFactorAuth/ClientCertificate/Certificates");
12141aa375b8SEd Tanous     std::array<std::string_view, 1> interfaces = {
12151aa375b8SEd Tanous         "xyz.openbmc_project.Certs.Certificate"};
12161aa375b8SEd Tanous     std::string path = "/xyz/openbmc_project/certs/authority/truststore";
12171aa375b8SEd Tanous 
12181aa375b8SEd Tanous     collection_util::getCollectionToKey(asyncResp, url, interfaces, path,
12191aa375b8SEd Tanous                                         keyLocation);
12201aa375b8SEd Tanous }
12211aa375b8SEd Tanous 
12221aa375b8SEd Tanous inline void handleAccountServiceClientCertificatesInstanceHead(
12231aa375b8SEd Tanous     App& app, const crow::Request& req,
12241aa375b8SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
12251aa375b8SEd Tanous     const std::string& /*id*/)
12261aa375b8SEd Tanous {
12271aa375b8SEd Tanous     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
12281aa375b8SEd Tanous     {
12291aa375b8SEd Tanous         return;
12301aa375b8SEd Tanous     }
12311aa375b8SEd Tanous 
12321aa375b8SEd Tanous     asyncResp->res.addHeader(
12331aa375b8SEd Tanous         boost::beast::http::field::link,
12341aa375b8SEd Tanous         "</redfish/v1/JsonSchemas/Certificate/Certificate.json>; rel=describedby");
12351aa375b8SEd Tanous }
12361aa375b8SEd Tanous 
12371aa375b8SEd Tanous inline void handleAccountServiceClientCertificatesInstanceGet(
12381aa375b8SEd Tanous     App& app, const crow::Request& req,
12391aa375b8SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id)
12401aa375b8SEd Tanous {
12411aa375b8SEd Tanous     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
12421aa375b8SEd Tanous     {
12431aa375b8SEd Tanous         return;
12441aa375b8SEd Tanous     }
12451aa375b8SEd Tanous     BMCWEB_LOG_DEBUG("ClientCertificate Certificate ID={}", id);
12461aa375b8SEd Tanous     const boost::urls::url certURL = boost::urls::format(
12471aa375b8SEd Tanous         "/redfish/v1/AccountService/MultiFactorAuth/ClientCertificate/Certificates/{}",
12481aa375b8SEd Tanous         id);
12491aa375b8SEd Tanous     std::string objPath =
12501aa375b8SEd Tanous         sdbusplus::message::object_path(certs::authorityObjectPath) / id;
12511aa375b8SEd Tanous     getCertificateProperties(
12521aa375b8SEd Tanous         asyncResp, objPath,
12531aa375b8SEd Tanous         "xyz.openbmc_project.Certs.Manager.Authority.Truststore", id, certURL,
12541aa375b8SEd Tanous         "Client Certificate");
12551aa375b8SEd Tanous }
12561aa375b8SEd Tanous 
12571aa375b8SEd Tanous inline void handleAccountServiceClientCertificatesHead(
12581aa375b8SEd Tanous     App& app, const crow::Request& req,
12591aa375b8SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
12601aa375b8SEd Tanous {
12611aa375b8SEd Tanous     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
12621aa375b8SEd Tanous     {
12631aa375b8SEd Tanous         return;
12641aa375b8SEd Tanous     }
12651aa375b8SEd Tanous 
12661aa375b8SEd Tanous     asyncResp->res.addHeader(
12671aa375b8SEd Tanous         boost::beast::http::field::link,
12681aa375b8SEd Tanous         "</redfish/v1/JsonSchemas/CertificateCollection/CertificateCollection.json>; rel=describedby");
12691aa375b8SEd Tanous }
12701aa375b8SEd Tanous 
12711aa375b8SEd Tanous inline void handleAccountServiceClientCertificatesGet(
12721aa375b8SEd Tanous     App& app, const crow::Request& req,
12731aa375b8SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
12741aa375b8SEd Tanous {
12751aa375b8SEd Tanous     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
12761aa375b8SEd Tanous     {
12771aa375b8SEd Tanous         return;
12781aa375b8SEd Tanous     }
12791aa375b8SEd Tanous     getClientCertificates(asyncResp, "/Members"_json_pointer);
12801aa375b8SEd Tanous }
12811aa375b8SEd Tanous 
12823ce3688aSEd Tanous using account_service::CertificateMappingAttribute;
12833ce3688aSEd Tanous using persistent_data::MTLSCommonNameParseMode;
12843ce3688aSEd Tanous inline CertificateMappingAttribute
12853ce3688aSEd Tanous     getCertificateMapping(MTLSCommonNameParseMode parse)
12863ce3688aSEd Tanous {
12873ce3688aSEd Tanous     switch (parse)
12883ce3688aSEd Tanous     {
12893ce3688aSEd Tanous         case MTLSCommonNameParseMode::CommonName:
12903ce3688aSEd Tanous         {
12913ce3688aSEd Tanous             return CertificateMappingAttribute::CommonName;
12923ce3688aSEd Tanous         }
12933ce3688aSEd Tanous         break;
12943ce3688aSEd Tanous         case MTLSCommonNameParseMode::Whole:
12953ce3688aSEd Tanous         {
12963ce3688aSEd Tanous             return CertificateMappingAttribute::Whole;
12973ce3688aSEd Tanous         }
12983ce3688aSEd Tanous         break;
12993ce3688aSEd Tanous         case MTLSCommonNameParseMode::UserPrincipalName:
13003ce3688aSEd Tanous         {
13013ce3688aSEd Tanous             return CertificateMappingAttribute::UserPrincipalName;
13023ce3688aSEd Tanous         }
13033ce3688aSEd Tanous         break;
13043ce3688aSEd Tanous 
13053ce3688aSEd Tanous         case MTLSCommonNameParseMode::Meta:
13063ce3688aSEd Tanous         {
13073ce3688aSEd Tanous             if constexpr (BMCWEB_META_TLS_COMMON_NAME_PARSING)
13083ce3688aSEd Tanous             {
13093ce3688aSEd Tanous                 return CertificateMappingAttribute::CommonName;
13103ce3688aSEd Tanous             }
13113ce3688aSEd Tanous         }
13123ce3688aSEd Tanous         break;
13133ce3688aSEd Tanous         default:
13143ce3688aSEd Tanous         {
13153ce3688aSEd Tanous             return CertificateMappingAttribute::Invalid;
13163ce3688aSEd Tanous         }
13173ce3688aSEd Tanous         break;
13183ce3688aSEd Tanous     }
13193ce3688aSEd Tanous }
13203ce3688aSEd Tanous 
13211aa375b8SEd Tanous inline void
13224c7d4d33SEd Tanous     handleAccountServiceGet(App& app, const crow::Request& req,
13234c7d4d33SEd Tanous                             const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
13244c7d4d33SEd Tanous {
1325afd369c6SJiaqing Zhao     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1326afd369c6SJiaqing Zhao     {
1327afd369c6SJiaqing Zhao         return;
1328afd369c6SJiaqing Zhao     }
13293e72c202SNinad Palsule 
13303e72c202SNinad Palsule     if (req.session == nullptr)
13313e72c202SNinad Palsule     {
13323e72c202SNinad Palsule         messages::internalError(asyncResp->res);
13333e72c202SNinad Palsule         return;
13343e72c202SNinad Palsule     }
13353e72c202SNinad Palsule 
1336c1019828SEd Tanous     const persistent_data::AuthConfigMethods& authMethodsConfig =
1337c1019828SEd Tanous         persistent_data::SessionStore::getInstance().getAuthMethodsConfig();
1338c1019828SEd Tanous 
1339afd369c6SJiaqing Zhao     asyncResp->res.addHeader(
1340afd369c6SJiaqing Zhao         boost::beast::http::field::link,
1341afd369c6SJiaqing Zhao         "</redfish/v1/JsonSchemas/AccountService/AccountService.json>; rel=describedby");
1342afd369c6SJiaqing Zhao 
13431476687dSEd Tanous     nlohmann::json& json = asyncResp->res.jsonValue;
13441476687dSEd Tanous     json["@odata.id"] = "/redfish/v1/AccountService";
1345482a69e7SRavi Teja     json["@odata.type"] = "#AccountService.v1_15_0.AccountService";
13461476687dSEd Tanous     json["Id"] = "AccountService";
13471476687dSEd Tanous     json["Name"] = "Account Service";
13481476687dSEd Tanous     json["Description"] = "Account Service";
13491476687dSEd Tanous     json["ServiceEnabled"] = true;
13501476687dSEd Tanous     json["MaxPasswordLength"] = 20;
13511ef4c342SEd Tanous     json["Accounts"]["@odata.id"] = "/redfish/v1/AccountService/Accounts";
13521476687dSEd Tanous     json["Roles"]["@odata.id"] = "/redfish/v1/AccountService/Roles";
1353482a69e7SRavi Teja     json["HTTPBasicAuth"] = authMethodsConfig.basic
1354482a69e7SRavi Teja                                 ? account_service::BasicAuthState::Enabled
1355482a69e7SRavi Teja                                 : account_service::BasicAuthState::Disabled;
1356482a69e7SRavi Teja 
1357482a69e7SRavi Teja     nlohmann::json::array_t allowed;
1358482a69e7SRavi Teja     allowed.emplace_back(account_service::BasicAuthState::Enabled);
1359482a69e7SRavi Teja     allowed.emplace_back(account_service::BasicAuthState::Disabled);
1360482a69e7SRavi Teja     json["HTTPBasicAuth@AllowableValues"] = std::move(allowed);
1361482a69e7SRavi Teja 
13621aa375b8SEd Tanous     nlohmann::json::object_t clientCertificate;
13631aa375b8SEd Tanous     clientCertificate["Enabled"] = authMethodsConfig.tls;
13643281bcf1SEd Tanous     clientCertificate["RespondToUnauthenticatedClients"] =
13653281bcf1SEd Tanous         !authMethodsConfig.tlsStrict;
13663ce3688aSEd Tanous 
13673ce3688aSEd Tanous     using account_service::CertificateMappingAttribute;
13683ce3688aSEd Tanous 
13693ce3688aSEd Tanous     CertificateMappingAttribute mapping =
13703ce3688aSEd Tanous         getCertificateMapping(authMethodsConfig.mTLSCommonNameParsingMode);
13713ce3688aSEd Tanous     if (mapping == CertificateMappingAttribute::Invalid)
13723ce3688aSEd Tanous     {
13733ce3688aSEd Tanous         messages::internalError(asyncResp->res);
13743ce3688aSEd Tanous     }
13753ce3688aSEd Tanous     else
13763ce3688aSEd Tanous     {
13773ce3688aSEd Tanous         clientCertificate["CertificateMappingAttribute"] = mapping;
13783ce3688aSEd Tanous     }
13791aa375b8SEd Tanous     nlohmann::json::object_t certificates;
13801aa375b8SEd Tanous     certificates["@odata.id"] =
13811aa375b8SEd Tanous         "/redfish/v1/AccountService/MultiFactorAuth/ClientCertificate/Certificates";
13821aa375b8SEd Tanous     certificates["@odata.type"] =
13831aa375b8SEd Tanous         "#CertificateCollection.CertificateCollection";
13841aa375b8SEd Tanous     clientCertificate["Certificates"] = std::move(certificates);
13851aa375b8SEd Tanous     json["MultiFactorAuth"]["ClientCertificate"] = std::move(clientCertificate);
13861aa375b8SEd Tanous 
13871aa375b8SEd Tanous     getClientCertificates(
13881aa375b8SEd Tanous         asyncResp,
13891aa375b8SEd Tanous         "/MultiFactorAuth/ClientCertificate/Certificates/Members"_json_pointer);
13901aa375b8SEd Tanous 
13911476687dSEd Tanous     json["Oem"]["OpenBMC"]["@odata.type"] =
13925b5574acSEd Tanous         "#OpenBMCAccountService.v1_0_0.AccountService";
13931476687dSEd Tanous     json["Oem"]["OpenBMC"]["@odata.id"] =
13941476687dSEd Tanous         "/redfish/v1/AccountService#/Oem/OpenBMC";
13951476687dSEd Tanous     json["Oem"]["OpenBMC"]["AuthMethods"]["BasicAuth"] =
13961476687dSEd Tanous         authMethodsConfig.basic;
13971476687dSEd Tanous     json["Oem"]["OpenBMC"]["AuthMethods"]["SessionToken"] =
13981476687dSEd Tanous         authMethodsConfig.sessionToken;
13991ef4c342SEd Tanous     json["Oem"]["OpenBMC"]["AuthMethods"]["XToken"] = authMethodsConfig.xtoken;
14001ef4c342SEd Tanous     json["Oem"]["OpenBMC"]["AuthMethods"]["Cookie"] = authMethodsConfig.cookie;
14011ef4c342SEd Tanous     json["Oem"]["OpenBMC"]["AuthMethods"]["TLS"] = authMethodsConfig.tls;
14021476687dSEd Tanous 
14031ef4c342SEd Tanous     // /redfish/v1/AccountService/LDAP/Certificates is something only
14041ef4c342SEd Tanous     // ConfigureManager can access then only display when the user has
14051ef4c342SEd Tanous     // permissions ConfigureManager
140672048780SAbhishek Patel     Privileges effectiveUserPrivileges =
14073e72c202SNinad Palsule         redfish::getUserPrivileges(*req.session);
140872048780SAbhishek Patel 
140972048780SAbhishek Patel     if (isOperationAllowedWithPrivileges({{"ConfigureManager"}},
141072048780SAbhishek Patel                                          effectiveUserPrivileges))
141172048780SAbhishek Patel     {
14121ef4c342SEd Tanous         asyncResp->res.jsonValue["LDAP"]["Certificates"]["@odata.id"] =
14131476687dSEd Tanous             "/redfish/v1/AccountService/LDAP/Certificates";
141472048780SAbhishek Patel     }
1415d1bde9e5SKrzysztof Grobelny     sdbusplus::asio::getAllProperties(
1416d1bde9e5SKrzysztof Grobelny         *crow::connections::systemBus, "xyz.openbmc_project.User.Manager",
1417d1bde9e5SKrzysztof Grobelny         "/xyz/openbmc_project/user", "xyz.openbmc_project.User.AccountPolicy",
14185e7e2dc5SEd Tanous         [asyncResp](const boost::system::error_code& ec,
14191ef4c342SEd Tanous                     const dbus::utility::DBusPropertiesMap& propertiesList) {
14203d958bbcSAppaRao Puli             if (ec)
14213d958bbcSAppaRao Puli             {
14223d958bbcSAppaRao Puli                 messages::internalError(asyncResp->res);
14233d958bbcSAppaRao Puli                 return;
14243d958bbcSAppaRao Puli             }
1425d1bde9e5SKrzysztof Grobelny 
142662598e31SEd Tanous             BMCWEB_LOG_DEBUG("Got {} properties for AccountService",
142762598e31SEd Tanous                              propertiesList.size());
1428d1bde9e5SKrzysztof Grobelny 
1429d1bde9e5SKrzysztof Grobelny             const uint8_t* minPasswordLength = nullptr;
1430d1bde9e5SKrzysztof Grobelny             const uint32_t* accountUnlockTimeout = nullptr;
1431d1bde9e5SKrzysztof Grobelny             const uint16_t* maxLoginAttemptBeforeLockout = nullptr;
1432d1bde9e5SKrzysztof Grobelny 
1433d1bde9e5SKrzysztof Grobelny             const bool success = sdbusplus::unpackPropertiesNoThrow(
1434d1bde9e5SKrzysztof Grobelny                 dbus_utils::UnpackErrorPrinter(), propertiesList,
1435d1bde9e5SKrzysztof Grobelny                 "MinPasswordLength", minPasswordLength, "AccountUnlockTimeout",
1436d1bde9e5SKrzysztof Grobelny                 accountUnlockTimeout, "MaxLoginAttemptBeforeLockout",
1437d1bde9e5SKrzysztof Grobelny                 maxLoginAttemptBeforeLockout);
1438d1bde9e5SKrzysztof Grobelny 
1439d1bde9e5SKrzysztof Grobelny             if (!success)
14403d958bbcSAppaRao Puli             {
1441d1bde9e5SKrzysztof Grobelny                 messages::internalError(asyncResp->res);
1442d1bde9e5SKrzysztof Grobelny                 return;
14433d958bbcSAppaRao Puli             }
1444d1bde9e5SKrzysztof Grobelny 
1445d1bde9e5SKrzysztof Grobelny             if (minPasswordLength != nullptr)
14463d958bbcSAppaRao Puli             {
1447bd79bce8SPatrick Williams                 asyncResp->res.jsonValue["MinPasswordLength"] =
1448bd79bce8SPatrick Williams                     *minPasswordLength;
14493d958bbcSAppaRao Puli             }
1450d1bde9e5SKrzysztof Grobelny 
1451d1bde9e5SKrzysztof Grobelny             if (accountUnlockTimeout != nullptr)
14523d958bbcSAppaRao Puli             {
1453d1bde9e5SKrzysztof Grobelny                 asyncResp->res.jsonValue["AccountLockoutDuration"] =
1454d1bde9e5SKrzysztof Grobelny                     *accountUnlockTimeout;
1455d1bde9e5SKrzysztof Grobelny             }
1456d1bde9e5SKrzysztof Grobelny 
1457d1bde9e5SKrzysztof Grobelny             if (maxLoginAttemptBeforeLockout != nullptr)
14583d958bbcSAppaRao Puli             {
1459002d39b4SEd Tanous                 asyncResp->res.jsonValue["AccountLockoutThreshold"] =
1460d1bde9e5SKrzysztof Grobelny                     *maxLoginAttemptBeforeLockout;
14613d958bbcSAppaRao Puli             }
1462d1bde9e5SKrzysztof Grobelny         });
14636973a582SRatan Gupta 
146402cad96eSEd Tanous     auto callback = [asyncResp](bool success, const LDAPConfigData& confData,
1465ab828d7cSRatan Gupta                                 const std::string& ldapType) {
1466cb13a392SEd Tanous         if (!success)
1467cb13a392SEd Tanous         {
1468cb13a392SEd Tanous             return;
1469cb13a392SEd Tanous         }
1470002d39b4SEd Tanous         parseLDAPConfigData(asyncResp->res.jsonValue, confData, ldapType);
1471ab828d7cSRatan Gupta     };
1472ab828d7cSRatan Gupta 
1473ab828d7cSRatan Gupta     getLDAPConfigData("LDAP", callback);
1474ab828d7cSRatan Gupta     getLDAPConfigData("ActiveDirectory", callback);
14751ef4c342SEd Tanous }
14766973a582SRatan Gupta 
1477bd79bce8SPatrick Williams inline void handleCertificateMappingAttributePatch(
1478bd79bce8SPatrick Williams     crow::Response& res, const std::string& certMapAttribute)
14793ce3688aSEd Tanous {
14803ce3688aSEd Tanous     MTLSCommonNameParseMode parseMode =
14813ce3688aSEd Tanous         persistent_data::getMTLSCommonNameParseMode(certMapAttribute);
14823ce3688aSEd Tanous     if (parseMode == MTLSCommonNameParseMode::Invalid)
14833ce3688aSEd Tanous     {
14843ce3688aSEd Tanous         messages::propertyValueNotInList(res, "CertificateMappingAttribute",
14853ce3688aSEd Tanous                                          certMapAttribute);
14863ce3688aSEd Tanous         return;
14873ce3688aSEd Tanous     }
14883ce3688aSEd Tanous 
14893ce3688aSEd Tanous     persistent_data::AuthConfigMethods& authMethodsConfig =
14903ce3688aSEd Tanous         persistent_data::SessionStore::getInstance().getAuthMethodsConfig();
14913ce3688aSEd Tanous     authMethodsConfig.mTLSCommonNameParsingMode = parseMode;
14923ce3688aSEd Tanous }
14933ce3688aSEd Tanous 
14943281bcf1SEd Tanous inline void handleRespondToUnauthenticatedClientsPatch(
14953281bcf1SEd Tanous     App& app, const crow::Request& req, crow::Response& res,
14963281bcf1SEd Tanous     bool respondToUnauthenticatedClients)
14973281bcf1SEd Tanous {
14983281bcf1SEd Tanous     if (req.session != nullptr)
14993281bcf1SEd Tanous     {
15003281bcf1SEd Tanous         // Sanity check.  If the user isn't currently authenticated with mutual
15013281bcf1SEd Tanous         // TLS, they very likely are about to permanently lock themselves out.
15023281bcf1SEd Tanous         // Make sure they're using mutual TLS before allowing locking.
15033281bcf1SEd Tanous         if (req.session->sessionType != persistent_data::SessionType::MutualTLS)
15043281bcf1SEd Tanous         {
15053281bcf1SEd Tanous             messages::propertyValueExternalConflict(
15063281bcf1SEd Tanous                 res,
15073281bcf1SEd Tanous                 "MultiFactorAuth/ClientCertificate/RespondToUnauthenticatedClients",
15083281bcf1SEd Tanous                 respondToUnauthenticatedClients);
15093281bcf1SEd Tanous             return;
15103281bcf1SEd Tanous         }
15113281bcf1SEd Tanous     }
15123281bcf1SEd Tanous 
15133281bcf1SEd Tanous     persistent_data::AuthConfigMethods& authMethodsConfig =
15143281bcf1SEd Tanous         persistent_data::SessionStore::getInstance().getAuthMethodsConfig();
15153281bcf1SEd Tanous 
15163281bcf1SEd Tanous     // Change the settings
15173281bcf1SEd Tanous     authMethodsConfig.tlsStrict = !respondToUnauthenticatedClients;
15183281bcf1SEd Tanous 
15193281bcf1SEd Tanous     // Write settings to disk
15203281bcf1SEd Tanous     persistent_data::getConfig().writeData();
15213281bcf1SEd Tanous 
15223281bcf1SEd Tanous     // Trigger a reload, to apply the new settings to new connections
15233281bcf1SEd Tanous     app.loadCertificate();
15243281bcf1SEd Tanous }
15253281bcf1SEd Tanous 
15261ef4c342SEd Tanous inline void handleAccountServicePatch(
15271ef4c342SEd Tanous     App& app, const crow::Request& req,
15281ef4c342SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
15291ef4c342SEd Tanous {
15303ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
153145ca1b86SEd Tanous     {
153245ca1b86SEd Tanous         return;
153345ca1b86SEd Tanous     }
1534f5ffd806SEd Tanous     std::optional<uint32_t> unlockTimeout;
1535f5ffd806SEd Tanous     std::optional<uint16_t> lockoutThreshold;
1536ef73ad0dSPaul Fertser     std::optional<uint8_t> minPasswordLength;
1537f5ffd806SEd Tanous     std::optional<uint16_t> maxPasswordLength;
153810cb44f3SEd Tanous     LdapPatchParams ldapObject;
15393ce3688aSEd Tanous     std::optional<std::string> certificateMappingAttribute;
15403281bcf1SEd Tanous     std::optional<bool> respondToUnauthenticatedClients;
154110cb44f3SEd Tanous     LdapPatchParams activeDirectoryObject;
1542c1019828SEd Tanous     AuthMethods auth;
1543482a69e7SRavi Teja     std::optional<std::string> httpBasicAuth;
15443ce3688aSEd Tanous 
1545c1019828SEd Tanous     // clang-format off
154615ed6780SWilly Tu     if (!json_util::readJsonPatch(
1547c1019828SEd Tanous             req, asyncResp->res,
1548c1019828SEd Tanous             "AccountLockoutDuration", unlockTimeout,
1549c1019828SEd Tanous             "AccountLockoutThreshold", lockoutThreshold,
155010cb44f3SEd Tanous             "ActiveDirectory/Authentication/AuthenticationType", activeDirectoryObject.authType,
155110cb44f3SEd Tanous             "ActiveDirectory/Authentication/Password", activeDirectoryObject.password,
155210cb44f3SEd Tanous             "ActiveDirectory/Authentication/Username", activeDirectoryObject.userName,
155310cb44f3SEd Tanous             "ActiveDirectory/LDAPService/SearchSettings/BaseDistinguishedNames", activeDirectoryObject.baseDNList,
155410cb44f3SEd Tanous             "ActiveDirectory/LDAPService/SearchSettings/GroupsAttribute", activeDirectoryObject.groupsAttribute,
155510cb44f3SEd Tanous             "ActiveDirectory/LDAPService/SearchSettings/UsernameAttribute", activeDirectoryObject.userNameAttribute,
155610cb44f3SEd Tanous             "ActiveDirectory/RemoteRoleMapping", activeDirectoryObject.remoteRoleMapData,
155710cb44f3SEd Tanous             "ActiveDirectory/ServiceAddresses", activeDirectoryObject.serviceAddressList,
155810cb44f3SEd Tanous             "ActiveDirectory/ServiceEnabled", activeDirectoryObject.serviceEnabled,
15593ce3688aSEd Tanous             "MultiFactorAuth/ClientCertificate/CertificateMappingAttribute", certificateMappingAttribute,
15603281bcf1SEd Tanous             "MultiFactorAuth/ClientCertificate/RespondToUnauthenticatedClients", respondToUnauthenticatedClients,
156110cb44f3SEd Tanous             "LDAP/Authentication/AuthenticationType", ldapObject.authType,
156210cb44f3SEd Tanous             "LDAP/Authentication/Password", ldapObject.password,
156310cb44f3SEd Tanous             "LDAP/Authentication/Username", ldapObject.userName,
156410cb44f3SEd Tanous             "LDAP/LDAPService/SearchSettings/BaseDistinguishedNames", ldapObject.baseDNList,
156510cb44f3SEd Tanous             "LDAP/LDAPService/SearchSettings/GroupsAttribute", ldapObject.groupsAttribute,
156610cb44f3SEd Tanous             "LDAP/LDAPService/SearchSettings/UsernameAttribute", ldapObject.userNameAttribute,
156710cb44f3SEd Tanous             "LDAP/RemoteRoleMapping", ldapObject.remoteRoleMapData,
156810cb44f3SEd Tanous             "LDAP/ServiceAddresses", ldapObject.serviceAddressList,
156910cb44f3SEd Tanous             "LDAP/ServiceEnabled", ldapObject.serviceEnabled,
1570c1019828SEd Tanous             "MaxPasswordLength", maxPasswordLength,
1571c1019828SEd Tanous             "MinPasswordLength", minPasswordLength,
1572c1019828SEd Tanous             "Oem/OpenBMC/AuthMethods/BasicAuth", auth.basicAuth,
1573c1019828SEd Tanous             "Oem/OpenBMC/AuthMethods/Cookie", auth.cookie,
1574c1019828SEd Tanous             "Oem/OpenBMC/AuthMethods/SessionToken", auth.sessionToken,
157510cb44f3SEd Tanous             "Oem/OpenBMC/AuthMethods/TLS", auth.tls,
1576482a69e7SRavi Teja             "Oem/OpenBMC/AuthMethods/XToken", auth.xToken,
1577482a69e7SRavi Teja             "HTTPBasicAuth", httpBasicAuth))
1578f5ffd806SEd Tanous     {
1579f5ffd806SEd Tanous         return;
1580f5ffd806SEd Tanous     }
1581c1019828SEd Tanous     // clang-format on
1582f5ffd806SEd Tanous 
1583482a69e7SRavi Teja     if (httpBasicAuth)
1584482a69e7SRavi Teja     {
1585482a69e7SRavi Teja         if (*httpBasicAuth == "Enabled")
1586482a69e7SRavi Teja         {
1587482a69e7SRavi Teja             auth.basicAuth = true;
1588482a69e7SRavi Teja         }
1589482a69e7SRavi Teja         else if (*httpBasicAuth == "Disabled")
1590482a69e7SRavi Teja         {
1591482a69e7SRavi Teja             auth.basicAuth = false;
1592482a69e7SRavi Teja         }
1593482a69e7SRavi Teja         else
1594482a69e7SRavi Teja         {
1595482a69e7SRavi Teja             messages::propertyValueNotInList(asyncResp->res, "HttpBasicAuth",
1596482a69e7SRavi Teja                                              *httpBasicAuth);
1597482a69e7SRavi Teja         }
1598482a69e7SRavi Teja     }
1599482a69e7SRavi Teja 
16003281bcf1SEd Tanous     if (respondToUnauthenticatedClients)
16013281bcf1SEd Tanous     {
16023281bcf1SEd Tanous         handleRespondToUnauthenticatedClientsPatch(
16033281bcf1SEd Tanous             app, req, asyncResp->res, *respondToUnauthenticatedClients);
16043281bcf1SEd Tanous     }
16053281bcf1SEd Tanous 
16063ce3688aSEd Tanous     if (certificateMappingAttribute)
16073ce3688aSEd Tanous     {
16083ce3688aSEd Tanous         handleCertificateMappingAttributePatch(asyncResp->res,
16093ce3688aSEd Tanous                                                *certificateMappingAttribute);
16103ce3688aSEd Tanous     }
16113ce3688aSEd Tanous 
1612f5ffd806SEd Tanous     if (minPasswordLength)
1613f5ffd806SEd Tanous     {
1614d02aad39SEd Tanous         setDbusProperty(
1615e93abac6SGinu George             asyncResp, "MinPasswordLength", "xyz.openbmc_project.User.Manager",
1616d02aad39SEd Tanous             sdbusplus::message::object_path("/xyz/openbmc_project/user"),
16179ae226faSGeorge Liu             "xyz.openbmc_project.User.AccountPolicy", "MinPasswordLength",
1618e93abac6SGinu George             *minPasswordLength);
1619f5ffd806SEd Tanous     }
1620f5ffd806SEd Tanous 
1621f5ffd806SEd Tanous     if (maxPasswordLength)
1622f5ffd806SEd Tanous     {
16231ef4c342SEd Tanous         messages::propertyNotWritable(asyncResp->res, "MaxPasswordLength");
1624f5ffd806SEd Tanous     }
1625f5ffd806SEd Tanous 
162610cb44f3SEd Tanous     handleLDAPPatch(std::move(activeDirectoryObject), asyncResp,
162710cb44f3SEd Tanous                     "ActiveDirectory");
162810cb44f3SEd Tanous     handleLDAPPatch(std::move(ldapObject), asyncResp, "LDAP");
1629f5ffd806SEd Tanous 
1630c1019828SEd Tanous     handleAuthMethodsPatch(asyncResp, auth);
1631f5ffd806SEd Tanous 
1632f5ffd806SEd Tanous     if (unlockTimeout)
1633f5ffd806SEd Tanous     {
1634d02aad39SEd Tanous         setDbusProperty(
1635e93abac6SGinu George             asyncResp, "AccountLockoutDuration",
1636e93abac6SGinu George             "xyz.openbmc_project.User.Manager",
1637d02aad39SEd Tanous             sdbusplus::message::object_path("/xyz/openbmc_project/user"),
16389ae226faSGeorge Liu             "xyz.openbmc_project.User.AccountPolicy", "AccountUnlockTimeout",
1639e93abac6SGinu George             *unlockTimeout);
1640f5ffd806SEd Tanous     }
1641f5ffd806SEd Tanous     if (lockoutThreshold)
1642f5ffd806SEd Tanous     {
1643d02aad39SEd Tanous         setDbusProperty(
1644e93abac6SGinu George             asyncResp, "AccountLockoutThreshold",
1645e93abac6SGinu George             "xyz.openbmc_project.User.Manager",
1646d02aad39SEd Tanous             sdbusplus::message::object_path("/xyz/openbmc_project/user"),
16479ae226faSGeorge Liu             "xyz.openbmc_project.User.AccountPolicy",
1648e93abac6SGinu George             "MaxLoginAttemptBeforeLockout", *lockoutThreshold);
1649f5ffd806SEd Tanous     }
16501ef4c342SEd Tanous }
1651f5ffd806SEd Tanous 
16524c7d4d33SEd Tanous inline void handleAccountCollectionHead(
16531ef4c342SEd Tanous     App& app, const crow::Request& req,
16541ef4c342SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
16551ef4c342SEd Tanous {
16563ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
165745ca1b86SEd Tanous     {
165845ca1b86SEd Tanous         return;
165945ca1b86SEd Tanous     }
16604c7d4d33SEd Tanous     asyncResp->res.addHeader(
16614c7d4d33SEd Tanous         boost::beast::http::field::link,
16624c7d4d33SEd Tanous         "</redfish/v1/JsonSchemas/ManagerAccountCollection.json>; rel=describedby");
16634c7d4d33SEd Tanous }
16644c7d4d33SEd Tanous 
16654c7d4d33SEd Tanous inline void handleAccountCollectionGet(
16664c7d4d33SEd Tanous     App& app, const crow::Request& req,
16674c7d4d33SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
16684c7d4d33SEd Tanous {
1669afd369c6SJiaqing Zhao     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1670afd369c6SJiaqing Zhao     {
1671afd369c6SJiaqing Zhao         return;
1672afd369c6SJiaqing Zhao     }
16733e72c202SNinad Palsule 
16743e72c202SNinad Palsule     if (req.session == nullptr)
16753e72c202SNinad Palsule     {
16763e72c202SNinad Palsule         messages::internalError(asyncResp->res);
16773e72c202SNinad Palsule         return;
16783e72c202SNinad Palsule     }
16793e72c202SNinad Palsule 
1680afd369c6SJiaqing Zhao     asyncResp->res.addHeader(
1681afd369c6SJiaqing Zhao         boost::beast::http::field::link,
1682afd369c6SJiaqing Zhao         "</redfish/v1/JsonSchemas/ManagerAccountCollection.json>; rel=describedby");
16831476687dSEd Tanous 
16841476687dSEd Tanous     asyncResp->res.jsonValue["@odata.id"] =
16851476687dSEd Tanous         "/redfish/v1/AccountService/Accounts";
16861ef4c342SEd Tanous     asyncResp->res.jsonValue["@odata.type"] = "#ManagerAccountCollection."
16871476687dSEd Tanous                                               "ManagerAccountCollection";
16881476687dSEd Tanous     asyncResp->res.jsonValue["Name"] = "Accounts Collection";
16891476687dSEd Tanous     asyncResp->res.jsonValue["Description"] = "BMC User Accounts";
16900f74e643SEd Tanous 
16916c51eab1SEd Tanous     Privileges effectiveUserPrivileges =
16923e72c202SNinad Palsule         redfish::getUserPrivileges(*req.session);
16936c51eab1SEd Tanous 
1694f5e29f33SJunLin Chen     std::string thisUser;
1695f5e29f33SJunLin Chen     if (req.session)
1696f5e29f33SJunLin Chen     {
1697f5e29f33SJunLin Chen         thisUser = req.session->username;
1698f5e29f33SJunLin Chen     }
16995eb468daSGeorge Liu     sdbusplus::message::object_path path("/xyz/openbmc_project/user");
17005eb468daSGeorge Liu     dbus::utility::getManagedObjects(
17015eb468daSGeorge Liu         "xyz.openbmc_project.User.Manager", path,
1702cef1ddfbSEd Tanous         [asyncResp, thisUser, effectiveUserPrivileges](
17035e7e2dc5SEd Tanous             const boost::system::error_code& ec,
1704711ac7a9SEd Tanous             const dbus::utility::ManagedObjectType& users) {
1705b9b2e0b2SEd Tanous             if (ec)
1706b9b2e0b2SEd Tanous             {
1707f12894f8SJason M. Bills                 messages::internalError(asyncResp->res);
1708b9b2e0b2SEd Tanous                 return;
1709b9b2e0b2SEd Tanous             }
1710b9b2e0b2SEd Tanous 
1711cef1ddfbSEd Tanous             bool userCanSeeAllAccounts =
1712002d39b4SEd Tanous                 effectiveUserPrivileges.isSupersetOf({"ConfigureUsers"});
1713cef1ddfbSEd Tanous 
1714cef1ddfbSEd Tanous             bool userCanSeeSelf =
1715002d39b4SEd Tanous                 effectiveUserPrivileges.isSupersetOf({"ConfigureSelf"});
1716cef1ddfbSEd Tanous 
1717002d39b4SEd Tanous             nlohmann::json& memberArray = asyncResp->res.jsonValue["Members"];
1718b9b2e0b2SEd Tanous             memberArray = nlohmann::json::array();
1719b9b2e0b2SEd Tanous 
17209eb808c1SEd Tanous             for (const auto& userpath : users)
1721b9b2e0b2SEd Tanous             {
17222dfd18efSEd Tanous                 std::string user = userpath.first.filename();
17232dfd18efSEd Tanous                 if (user.empty())
1724b9b2e0b2SEd Tanous                 {
17252dfd18efSEd Tanous                     messages::internalError(asyncResp->res);
172662598e31SEd Tanous                     BMCWEB_LOG_ERROR("Invalid firmware ID");
17272dfd18efSEd Tanous 
17282dfd18efSEd Tanous                     return;
1729b9b2e0b2SEd Tanous                 }
1730f365910cSGunnar Mills 
1731f365910cSGunnar Mills                 // As clarified by Redfish here:
1732f365910cSGunnar Mills                 // https://redfishforum.com/thread/281/manageraccountcollection-change-allows-account-enumeration
17336c51eab1SEd Tanous                 // Users without ConfigureUsers, only see their own
17346c51eab1SEd Tanous                 // account. Users with ConfigureUsers, see all
17356c51eab1SEd Tanous                 // accounts.
1736bd79bce8SPatrick Williams                 if (userCanSeeAllAccounts ||
1737bd79bce8SPatrick Williams                     (thisUser == user && userCanSeeSelf))
1738f365910cSGunnar Mills                 {
17391476687dSEd Tanous                     nlohmann::json::object_t member;
17403b32780dSEd Tanous                     member["@odata.id"] = boost::urls::format(
17413b32780dSEd Tanous                         "/redfish/v1/AccountService/Accounts/{}", user);
1742b2ba3072SPatrick Williams                     memberArray.emplace_back(std::move(member));
1743b9b2e0b2SEd Tanous                 }
1744f365910cSGunnar Mills             }
1745bd79bce8SPatrick Williams             asyncResp->res.jsonValue["Members@odata.count"] =
1746bd79bce8SPatrick Williams                 memberArray.size();
17475eb468daSGeorge Liu         });
17481ef4c342SEd Tanous }
17496c51eab1SEd Tanous 
175097e90da3SNinad Palsule inline void processAfterCreateUser(
175197e90da3SNinad Palsule     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
175297e90da3SNinad Palsule     const std::string& username, const std::string& password,
175397e90da3SNinad Palsule     const boost::system::error_code& ec, sdbusplus::message_t& m)
175497e90da3SNinad Palsule {
175597e90da3SNinad Palsule     if (ec)
175697e90da3SNinad Palsule     {
175797e90da3SNinad Palsule         userErrorMessageHandler(m.get_error(), asyncResp, username, "");
175897e90da3SNinad Palsule         return;
175997e90da3SNinad Palsule     }
176097e90da3SNinad Palsule 
176197e90da3SNinad Palsule     if (pamUpdatePassword(username, password) != PAM_SUCCESS)
176297e90da3SNinad Palsule     {
176397e90da3SNinad Palsule         // At this point we have a user that's been
176497e90da3SNinad Palsule         // created, but the password set
176597e90da3SNinad Palsule         // failed.Something is wrong, so delete the user
176697e90da3SNinad Palsule         // that we've already created
176797e90da3SNinad Palsule         sdbusplus::message::object_path tempObjPath(rootUserDbusPath);
176897e90da3SNinad Palsule         tempObjPath /= username;
176997e90da3SNinad Palsule         const std::string userPath(tempObjPath);
177097e90da3SNinad Palsule 
177197e90da3SNinad Palsule         crow::connections::systemBus->async_method_call(
177297e90da3SNinad Palsule             [asyncResp, password](const boost::system::error_code& ec3) {
177397e90da3SNinad Palsule                 if (ec3)
177497e90da3SNinad Palsule                 {
177597e90da3SNinad Palsule                     messages::internalError(asyncResp->res);
177697e90da3SNinad Palsule                     return;
177797e90da3SNinad Palsule                 }
177897e90da3SNinad Palsule 
177997e90da3SNinad Palsule                 // If password is invalid
17809bd80831SJason M. Bills                 messages::propertyValueFormatError(asyncResp->res, nullptr,
178197e90da3SNinad Palsule                                                    "Password");
178297e90da3SNinad Palsule             },
178397e90da3SNinad Palsule             "xyz.openbmc_project.User.Manager", userPath,
178497e90da3SNinad Palsule             "xyz.openbmc_project.Object.Delete", "Delete");
178597e90da3SNinad Palsule 
178662598e31SEd Tanous         BMCWEB_LOG_ERROR("pamUpdatePassword Failed");
178797e90da3SNinad Palsule         return;
178897e90da3SNinad Palsule     }
178997e90da3SNinad Palsule 
179097e90da3SNinad Palsule     messages::created(asyncResp->res);
179197e90da3SNinad Palsule     asyncResp->res.addHeader("Location",
179297e90da3SNinad Palsule                              "/redfish/v1/AccountService/Accounts/" + username);
179397e90da3SNinad Palsule }
179497e90da3SNinad Palsule 
179597e90da3SNinad Palsule inline void processAfterGetAllGroups(
179697e90da3SNinad Palsule     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
179797e90da3SNinad Palsule     const std::string& username, const std::string& password,
1798e01d0c36SEd Tanous     const std::string& roleId, bool enabled,
17999ba73934SNinad Palsule     std::optional<std::vector<std::string>> accountTypes,
180097e90da3SNinad Palsule     const std::vector<std::string>& allGroupsList)
180197e90da3SNinad Palsule {
18023e72c202SNinad Palsule     std::vector<std::string> userGroups;
18039ba73934SNinad Palsule     std::vector<std::string> accountTypeUserGroups;
18049ba73934SNinad Palsule 
18059ba73934SNinad Palsule     // If user specified account types then convert them to unix user groups
18069ba73934SNinad Palsule     if (accountTypes)
18079ba73934SNinad Palsule     {
18089ba73934SNinad Palsule         if (!getUserGroupFromAccountType(asyncResp->res, *accountTypes,
18099ba73934SNinad Palsule                                          accountTypeUserGroups))
18109ba73934SNinad Palsule         {
18119ba73934SNinad Palsule             // Problem in mapping Account Types to User Groups, Error already
18129ba73934SNinad Palsule             // logged.
18139ba73934SNinad Palsule             return;
18149ba73934SNinad Palsule         }
18159ba73934SNinad Palsule     }
18169ba73934SNinad Palsule 
18173e72c202SNinad Palsule     for (const auto& grp : allGroupsList)
18183e72c202SNinad Palsule     {
18199ba73934SNinad Palsule         // If user specified the account type then only accept groups which are
18209ba73934SNinad Palsule         // in the account types group list.
18219ba73934SNinad Palsule         if (!accountTypeUserGroups.empty())
18229ba73934SNinad Palsule         {
18239ba73934SNinad Palsule             bool found = false;
18249ba73934SNinad Palsule             for (const auto& grp1 : accountTypeUserGroups)
18259ba73934SNinad Palsule             {
18269ba73934SNinad Palsule                 if (grp == grp1)
18279ba73934SNinad Palsule                 {
18289ba73934SNinad Palsule                     found = true;
18299ba73934SNinad Palsule                     break;
18309ba73934SNinad Palsule                 }
18319ba73934SNinad Palsule             }
18329ba73934SNinad Palsule             if (!found)
18339ba73934SNinad Palsule             {
18349ba73934SNinad Palsule                 continue;
18359ba73934SNinad Palsule             }
18369ba73934SNinad Palsule         }
18379ba73934SNinad Palsule 
18383e72c202SNinad Palsule         // Console access is provided to the user who is a member of
18393e72c202SNinad Palsule         // hostconsole group and has a administrator role. So, set
18403e72c202SNinad Palsule         // hostconsole group only for the administrator.
18419ba73934SNinad Palsule         if ((grp == "hostconsole") && (roleId != "priv-admin"))
18423e72c202SNinad Palsule         {
18439ba73934SNinad Palsule             if (!accountTypeUserGroups.empty())
18449ba73934SNinad Palsule             {
184562598e31SEd Tanous                 BMCWEB_LOG_ERROR(
184662598e31SEd Tanous                     "Only administrator can get HostConsole access");
18479ba73934SNinad Palsule                 asyncResp->res.result(boost::beast::http::status::bad_request);
18489ba73934SNinad Palsule                 return;
18499ba73934SNinad Palsule             }
18509ba73934SNinad Palsule             continue;
18519ba73934SNinad Palsule         }
18523e72c202SNinad Palsule         userGroups.emplace_back(grp);
18533e72c202SNinad Palsule     }
18549ba73934SNinad Palsule 
18559ba73934SNinad Palsule     // Make sure user specified groups are valid. This is internal error because
18569ba73934SNinad Palsule     // it some inconsistencies between user manager and bmcweb.
18579ba73934SNinad Palsule     if (!accountTypeUserGroups.empty() &&
18589ba73934SNinad Palsule         accountTypeUserGroups.size() != userGroups.size())
18599ba73934SNinad Palsule     {
18609ba73934SNinad Palsule         messages::internalError(asyncResp->res);
18619ba73934SNinad Palsule         return;
18623e72c202SNinad Palsule     }
186397e90da3SNinad Palsule     crow::connections::systemBus->async_method_call(
186497e90da3SNinad Palsule         [asyncResp, username, password](const boost::system::error_code& ec2,
186597e90da3SNinad Palsule                                         sdbusplus::message_t& m) {
186697e90da3SNinad Palsule             processAfterCreateUser(asyncResp, username, password, ec2, m);
186797e90da3SNinad Palsule         },
186897e90da3SNinad Palsule         "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
18693e72c202SNinad Palsule         "xyz.openbmc_project.User.Manager", "CreateUser", username, userGroups,
1870e01d0c36SEd Tanous         roleId, enabled);
187197e90da3SNinad Palsule }
187297e90da3SNinad Palsule 
18731ef4c342SEd Tanous inline void handleAccountCollectionPost(
18741ef4c342SEd Tanous     App& app, const crow::Request& req,
18751ef4c342SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
18761ef4c342SEd Tanous {
18773ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
187845ca1b86SEd Tanous     {
187945ca1b86SEd Tanous         return;
188045ca1b86SEd Tanous     }
18819712f8acSEd Tanous     std::string username;
18829712f8acSEd Tanous     std::string password;
1883e01d0c36SEd Tanous     std::optional<std::string> roleIdJson;
1884e01d0c36SEd Tanous     std::optional<bool> enabledJson;
18859ba73934SNinad Palsule     std::optional<std::vector<std::string>> accountTypes;
1886bd79bce8SPatrick Williams     if (!json_util::readJsonPatch(
1887bd79bce8SPatrick Williams             req, asyncResp->res, "UserName", username, "Password", password,
1888bd79bce8SPatrick Williams             "RoleId", roleIdJson, "Enabled", enabledJson, "AccountTypes",
1889e01d0c36SEd Tanous             accountTypes))
189004ae99ecSEd Tanous     {
189104ae99ecSEd Tanous         return;
189204ae99ecSEd Tanous     }
189304ae99ecSEd Tanous 
1894e01d0c36SEd Tanous     std::string roleId = roleIdJson.value_or("User");
1895e01d0c36SEd Tanous     std::string priv = getPrivilegeFromRoleId(roleId);
189684e12cb7SAppaRao Puli     if (priv.empty())
189704ae99ecSEd Tanous     {
1898e01d0c36SEd Tanous         messages::propertyValueNotInList(asyncResp->res, roleId, "RoleId");
189904ae99ecSEd Tanous         return;
190004ae99ecSEd Tanous     }
19019712f8acSEd Tanous     roleId = priv;
190204ae99ecSEd Tanous 
1903e01d0c36SEd Tanous     bool enabled = enabledJson.value_or(true);
1904e01d0c36SEd Tanous 
1905599c71d8SAyushi Smriti     // Reading AllGroups property
19061e1e598dSJonathan Doman     sdbusplus::asio::getProperty<std::vector<std::string>>(
19071ef4c342SEd Tanous         *crow::connections::systemBus, "xyz.openbmc_project.User.Manager",
19081ef4c342SEd Tanous         "/xyz/openbmc_project/user", "xyz.openbmc_project.User.Manager",
19091ef4c342SEd Tanous         "AllGroups",
19109ba73934SNinad Palsule         [asyncResp, username, password{std::move(password)}, roleId, enabled,
19119ba73934SNinad Palsule          accountTypes](const boost::system::error_code& ec,
19121e1e598dSJonathan Doman                        const std::vector<std::string>& allGroupsList) {
1913599c71d8SAyushi Smriti             if (ec)
1914599c71d8SAyushi Smriti             {
1915a0735a4eSGunnar Mills                 BMCWEB_LOG_ERROR("D-Bus response error {}", ec);
1916599c71d8SAyushi Smriti                 messages::internalError(asyncResp->res);
1917599c71d8SAyushi Smriti                 return;
1918599c71d8SAyushi Smriti             }
1919599c71d8SAyushi Smriti 
19201e1e598dSJonathan Doman             if (allGroupsList.empty())
1921599c71d8SAyushi Smriti             {
1922599c71d8SAyushi Smriti                 messages::internalError(asyncResp->res);
1923599c71d8SAyushi Smriti                 return;
1924599c71d8SAyushi Smriti             }
1925599c71d8SAyushi Smriti 
1926bd79bce8SPatrick Williams             processAfterGetAllGroups(asyncResp, username, password, roleId,
1927bd79bce8SPatrick Williams                                      enabled, accountTypes, allGroupsList);
19281e1e598dSJonathan Doman         });
19291ef4c342SEd Tanous }
1930b9b2e0b2SEd Tanous 
19311ef4c342SEd Tanous inline void
19324c7d4d33SEd Tanous     handleAccountHead(App& app, const crow::Request& req,
19336c51eab1SEd Tanous                       const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
19344c7d4d33SEd Tanous                       const std::string& /*accountName*/)
19351ef4c342SEd Tanous {
19363ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
193745ca1b86SEd Tanous     {
193845ca1b86SEd Tanous         return;
193945ca1b86SEd Tanous     }
19404c7d4d33SEd Tanous     asyncResp->res.addHeader(
19414c7d4d33SEd Tanous         boost::beast::http::field::link,
19424c7d4d33SEd Tanous         "</redfish/v1/JsonSchemas/ManagerAccount/ManagerAccount.json>; rel=describedby");
19434c7d4d33SEd Tanous }
1944afd369c6SJiaqing Zhao 
19454c7d4d33SEd Tanous inline void
19464c7d4d33SEd Tanous     handleAccountGet(App& app, const crow::Request& req,
19474c7d4d33SEd Tanous                      const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
19484c7d4d33SEd Tanous                      const std::string& accountName)
19494c7d4d33SEd Tanous {
1950afd369c6SJiaqing Zhao     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1951afd369c6SJiaqing Zhao     {
1952afd369c6SJiaqing Zhao         return;
1953afd369c6SJiaqing Zhao     }
1954afd369c6SJiaqing Zhao     asyncResp->res.addHeader(
1955afd369c6SJiaqing Zhao         boost::beast::http::field::link,
1956afd369c6SJiaqing Zhao         "</redfish/v1/JsonSchemas/ManagerAccount/ManagerAccount.json>; rel=describedby");
1957afd369c6SJiaqing Zhao 
195825b54dbaSEd Tanous     if constexpr (BMCWEB_INSECURE_DISABLE_AUTH)
195925b54dbaSEd Tanous     {
1960031514fbSJunLin Chen         // If authentication is disabled, there are no user accounts
196125b54dbaSEd Tanous         messages::resourceNotFound(asyncResp->res, "ManagerAccount",
196225b54dbaSEd Tanous                                    accountName);
1963031514fbSJunLin Chen         return;
196425b54dbaSEd Tanous     }
1965afd369c6SJiaqing Zhao 
1966031514fbSJunLin Chen     if (req.session == nullptr)
1967031514fbSJunLin Chen     {
1968031514fbSJunLin Chen         messages::internalError(asyncResp->res);
1969031514fbSJunLin Chen         return;
1970031514fbSJunLin Chen     }
19716c51eab1SEd Tanous     if (req.session->username != accountName)
1972b9b2e0b2SEd Tanous     {
19736c51eab1SEd Tanous         // At this point we've determined that the user is trying to
19741ef4c342SEd Tanous         // modify a user that isn't them.  We need to verify that they
19751ef4c342SEd Tanous         // have permissions to modify other users, so re-run the auth
19761ef4c342SEd Tanous         // check with the same permissions, minus ConfigureSelf.
19776c51eab1SEd Tanous         Privileges effectiveUserPrivileges =
19783e72c202SNinad Palsule             redfish::getUserPrivileges(*req.session);
19791ef4c342SEd Tanous         Privileges requiredPermissionsToChangeNonSelf = {"ConfigureUsers",
19801ef4c342SEd Tanous                                                          "ConfigureManager"};
19816c51eab1SEd Tanous         if (!effectiveUserPrivileges.isSupersetOf(
19826c51eab1SEd Tanous                 requiredPermissionsToChangeNonSelf))
1983900f9497SJoseph Reynolds         {
198462598e31SEd Tanous             BMCWEB_LOG_DEBUG("GET Account denied access");
1985900f9497SJoseph Reynolds             messages::insufficientPrivilege(asyncResp->res);
1986900f9497SJoseph Reynolds             return;
1987900f9497SJoseph Reynolds         }
1988900f9497SJoseph Reynolds     }
1989900f9497SJoseph Reynolds 
19905eb468daSGeorge Liu     sdbusplus::message::object_path path("/xyz/openbmc_project/user");
19915eb468daSGeorge Liu     dbus::utility::getManagedObjects(
19925eb468daSGeorge Liu         "xyz.openbmc_project.User.Manager", path,
19931ef4c342SEd Tanous         [asyncResp,
19945e7e2dc5SEd Tanous          accountName](const boost::system::error_code& ec,
1995711ac7a9SEd Tanous                       const dbus::utility::ManagedObjectType& users) {
1996b9b2e0b2SEd Tanous             if (ec)
1997b9b2e0b2SEd Tanous             {
1998f12894f8SJason M. Bills                 messages::internalError(asyncResp->res);
1999b9b2e0b2SEd Tanous                 return;
2000b9b2e0b2SEd Tanous             }
20013544d2a7SEd Tanous             const auto userIt = std::ranges::find_if(
200280f79a40SMichael Shen                 users,
200380f79a40SMichael Shen                 [accountName](
2004b477fd44SP Dheeraj Srujan Kumar                     const std::pair<sdbusplus::message::object_path,
200580f79a40SMichael Shen                                     dbus::utility::DBusInterfacesMap>& user) {
200655f79e6fSEd Tanous                     return accountName == user.first.filename();
2007b477fd44SP Dheeraj Srujan Kumar                 });
2008b9b2e0b2SEd Tanous 
200984e12cb7SAppaRao Puli             if (userIt == users.end())
2010b9b2e0b2SEd Tanous             {
2011002d39b4SEd Tanous                 messages::resourceNotFound(asyncResp->res, "ManagerAccount",
2012002d39b4SEd Tanous                                            accountName);
201384e12cb7SAppaRao Puli                 return;
201484e12cb7SAppaRao Puli             }
20154e68c45bSAyushi Smriti 
20161476687dSEd Tanous             asyncResp->res.jsonValue["@odata.type"] =
201758345856SAbhishek Patel                 "#ManagerAccount.v1_7_0.ManagerAccount";
20181476687dSEd Tanous             asyncResp->res.jsonValue["Name"] = "User Account";
20191476687dSEd Tanous             asyncResp->res.jsonValue["Description"] = "User Account";
20201476687dSEd Tanous             asyncResp->res.jsonValue["Password"] = nullptr;
202158345856SAbhishek Patel             asyncResp->res.jsonValue["StrictAccountTypes"] = true;
20224e68c45bSAyushi Smriti 
202384e12cb7SAppaRao Puli             for (const auto& interface : userIt->second)
202465b0dc32SEd Tanous             {
2025002d39b4SEd Tanous                 if (interface.first == "xyz.openbmc_project.User.Attributes")
202665b0dc32SEd Tanous                 {
202765b0dc32SEd Tanous                     for (const auto& property : interface.second)
202865b0dc32SEd Tanous                     {
202965b0dc32SEd Tanous                         if (property.first == "UserEnabled")
203065b0dc32SEd Tanous                         {
203165b0dc32SEd Tanous                             const bool* userEnabled =
2032abf2add6SEd Tanous                                 std::get_if<bool>(&property.second);
203365b0dc32SEd Tanous                             if (userEnabled == nullptr)
203465b0dc32SEd Tanous                             {
203562598e31SEd Tanous                                 BMCWEB_LOG_ERROR("UserEnabled wasn't a bool");
203684e12cb7SAppaRao Puli                                 messages::internalError(asyncResp->res);
203784e12cb7SAppaRao Puli                                 return;
203865b0dc32SEd Tanous                             }
2039002d39b4SEd Tanous                             asyncResp->res.jsonValue["Enabled"] = *userEnabled;
204065b0dc32SEd Tanous                         }
2041002d39b4SEd Tanous                         else if (property.first == "UserLockedForFailedAttempt")
204265b0dc32SEd Tanous                         {
204365b0dc32SEd Tanous                             const bool* userLocked =
2044abf2add6SEd Tanous                                 std::get_if<bool>(&property.second);
204565b0dc32SEd Tanous                             if (userLocked == nullptr)
204665b0dc32SEd Tanous                             {
204762598e31SEd Tanous                                 BMCWEB_LOG_ERROR("UserLockedForF"
204884e12cb7SAppaRao Puli                                                  "ailedAttempt "
204962598e31SEd Tanous                                                  "wasn't a bool");
205084e12cb7SAppaRao Puli                                 messages::internalError(asyncResp->res);
205184e12cb7SAppaRao Puli                                 return;
205265b0dc32SEd Tanous                             }
2053002d39b4SEd Tanous                             asyncResp->res.jsonValue["Locked"] = *userLocked;
205420fa6a2cSEd Tanous                             nlohmann::json::array_t allowed;
205520fa6a2cSEd Tanous                             // can only unlock accounts
205620fa6a2cSEd Tanous                             allowed.emplace_back("false");
2057002d39b4SEd Tanous                             asyncResp->res
205820fa6a2cSEd Tanous                                 .jsonValue["Locked@Redfish.AllowableValues"] =
205920fa6a2cSEd Tanous                                 std::move(allowed);
206065b0dc32SEd Tanous                         }
206184e12cb7SAppaRao Puli                         else if (property.first == "UserPrivilege")
206284e12cb7SAppaRao Puli                         {
206354fc587aSNagaraju Goruganti                             const std::string* userPrivPtr =
2064002d39b4SEd Tanous                                 std::get_if<std::string>(&property.second);
206554fc587aSNagaraju Goruganti                             if (userPrivPtr == nullptr)
206684e12cb7SAppaRao Puli                             {
206762598e31SEd Tanous                                 BMCWEB_LOG_ERROR("UserPrivilege wasn't a "
206862598e31SEd Tanous                                                  "string");
206984e12cb7SAppaRao Puli                                 messages::internalError(asyncResp->res);
207084e12cb7SAppaRao Puli                                 return;
207184e12cb7SAppaRao Puli                             }
2072bd79bce8SPatrick Williams                             std::string role =
2073bd79bce8SPatrick Williams                                 getRoleIdFromPrivilege(*userPrivPtr);
207454fc587aSNagaraju Goruganti                             if (role.empty())
207584e12cb7SAppaRao Puli                             {
207662598e31SEd Tanous                                 BMCWEB_LOG_ERROR("Invalid user role");
207784e12cb7SAppaRao Puli                                 messages::internalError(asyncResp->res);
207884e12cb7SAppaRao Puli                                 return;
207984e12cb7SAppaRao Puli                             }
208054fc587aSNagaraju Goruganti                             asyncResp->res.jsonValue["RoleId"] = role;
208184e12cb7SAppaRao Puli 
20821476687dSEd Tanous                             nlohmann::json& roleEntry =
2083002d39b4SEd Tanous                                 asyncResp->res.jsonValue["Links"]["Role"];
20843b32780dSEd Tanous                             roleEntry["@odata.id"] = boost::urls::format(
20853b32780dSEd Tanous                                 "/redfish/v1/AccountService/Roles/{}", role);
208684e12cb7SAppaRao Puli                         }
2087002d39b4SEd Tanous                         else if (property.first == "UserPasswordExpired")
20883bf4e632SJoseph Reynolds                         {
20893bf4e632SJoseph Reynolds                             const bool* userPasswordExpired =
20903bf4e632SJoseph Reynolds                                 std::get_if<bool>(&property.second);
20913bf4e632SJoseph Reynolds                             if (userPasswordExpired == nullptr)
20923bf4e632SJoseph Reynolds                             {
209362598e31SEd Tanous                                 BMCWEB_LOG_ERROR(
209462598e31SEd Tanous                                     "UserPasswordExpired wasn't a bool");
20953bf4e632SJoseph Reynolds                                 messages::internalError(asyncResp->res);
20963bf4e632SJoseph Reynolds                                 return;
20973bf4e632SJoseph Reynolds                             }
2098002d39b4SEd Tanous                             asyncResp->res.jsonValue["PasswordChangeRequired"] =
20993bf4e632SJoseph Reynolds                                 *userPasswordExpired;
21003bf4e632SJoseph Reynolds                         }
2101c7229815SAbhishek Patel                         else if (property.first == "UserGroups")
2102c7229815SAbhishek Patel                         {
2103c7229815SAbhishek Patel                             const std::vector<std::string>* userGroups =
2104c7229815SAbhishek Patel                                 std::get_if<std::vector<std::string>>(
2105c7229815SAbhishek Patel                                     &property.second);
2106c7229815SAbhishek Patel                             if (userGroups == nullptr)
2107c7229815SAbhishek Patel                             {
210862598e31SEd Tanous                                 BMCWEB_LOG_ERROR(
210962598e31SEd Tanous                                     "userGroups wasn't a string vector");
2110c7229815SAbhishek Patel                                 messages::internalError(asyncResp->res);
2111c7229815SAbhishek Patel                                 return;
2112c7229815SAbhishek Patel                             }
2113bd79bce8SPatrick Williams                             if (!translateUserGroup(*userGroups,
2114bd79bce8SPatrick Williams                                                     asyncResp->res))
2115c7229815SAbhishek Patel                             {
211662598e31SEd Tanous                                 BMCWEB_LOG_ERROR("userGroups mapping failed");
2117c7229815SAbhishek Patel                                 messages::internalError(asyncResp->res);
2118c7229815SAbhishek Patel                                 return;
2119c7229815SAbhishek Patel                             }
2120c7229815SAbhishek Patel                         }
212165b0dc32SEd Tanous                     }
212265b0dc32SEd Tanous                 }
212365b0dc32SEd Tanous             }
212465b0dc32SEd Tanous 
21253b32780dSEd Tanous             asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
21263b32780dSEd Tanous                 "/redfish/v1/AccountService/Accounts/{}", accountName);
2127b9b2e0b2SEd Tanous             asyncResp->res.jsonValue["Id"] = accountName;
2128b9b2e0b2SEd Tanous             asyncResp->res.jsonValue["UserName"] = accountName;
21295eb468daSGeorge Liu         });
21301ef4c342SEd Tanous }
2131a840879dSEd Tanous 
21321ef4c342SEd Tanous inline void
213320fc307fSGunnar Mills     handleAccountDelete(App& app, const crow::Request& req,
21346c51eab1SEd Tanous                         const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
21351ef4c342SEd Tanous                         const std::string& username)
21361ef4c342SEd Tanous {
21373ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
213845ca1b86SEd Tanous     {
213945ca1b86SEd Tanous         return;
214045ca1b86SEd Tanous     }
21411ef4c342SEd Tanous 
214225b54dbaSEd Tanous     if constexpr (BMCWEB_INSECURE_DISABLE_AUTH)
214325b54dbaSEd Tanous     {
2144031514fbSJunLin Chen         // If authentication is disabled, there are no user accounts
2145d8a5d5d8SJiaqing Zhao         messages::resourceNotFound(asyncResp->res, "ManagerAccount", username);
2146031514fbSJunLin Chen         return;
214725b54dbaSEd Tanous     }
21481ef4c342SEd Tanous     sdbusplus::message::object_path tempObjPath(rootUserDbusPath);
21491ef4c342SEd Tanous     tempObjPath /= username;
21501ef4c342SEd Tanous     const std::string userPath(tempObjPath);
21511ef4c342SEd Tanous 
21521ef4c342SEd Tanous     crow::connections::systemBus->async_method_call(
21535e7e2dc5SEd Tanous         [asyncResp, username](const boost::system::error_code& ec) {
21541ef4c342SEd Tanous             if (ec)
21551ef4c342SEd Tanous             {
2156d8a5d5d8SJiaqing Zhao                 messages::resourceNotFound(asyncResp->res, "ManagerAccount",
21571ef4c342SEd Tanous                                            username);
21581ef4c342SEd Tanous                 return;
21591ef4c342SEd Tanous             }
21601ef4c342SEd Tanous 
21611ef4c342SEd Tanous             messages::accountRemoved(asyncResp->res);
21621ef4c342SEd Tanous         },
21631ef4c342SEd Tanous         "xyz.openbmc_project.User.Manager", userPath,
21641ef4c342SEd Tanous         "xyz.openbmc_project.Object.Delete", "Delete");
21651ef4c342SEd Tanous }
21661ef4c342SEd Tanous 
21671ef4c342SEd Tanous inline void
21681ef4c342SEd Tanous     handleAccountPatch(App& app, const crow::Request& req,
21691ef4c342SEd Tanous                        const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
21701ef4c342SEd Tanous                        const std::string& username)
21711ef4c342SEd Tanous {
21721ef4c342SEd Tanous     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
21731ef4c342SEd Tanous     {
21741ef4c342SEd Tanous         return;
21751ef4c342SEd Tanous     }
217625b54dbaSEd Tanous     if constexpr (BMCWEB_INSECURE_DISABLE_AUTH)
217725b54dbaSEd Tanous     {
21781ef4c342SEd Tanous         // If authentication is disabled, there are no user accounts
2179d8a5d5d8SJiaqing Zhao         messages::resourceNotFound(asyncResp->res, "ManagerAccount", username);
21801ef4c342SEd Tanous         return;
218125b54dbaSEd Tanous     }
2182a24526dcSEd Tanous     std::optional<std::string> newUserName;
2183a24526dcSEd Tanous     std::optional<std::string> password;
2184a24526dcSEd Tanous     std::optional<bool> enabled;
2185a24526dcSEd Tanous     std::optional<std::string> roleId;
218624c8542dSRatan Gupta     std::optional<bool> locked;
218758345856SAbhishek Patel     std::optional<std::vector<std::string>> accountTypes;
218858345856SAbhishek Patel 
2189031514fbSJunLin Chen     if (req.session == nullptr)
2190031514fbSJunLin Chen     {
2191031514fbSJunLin Chen         messages::internalError(asyncResp->res);
2192031514fbSJunLin Chen         return;
2193031514fbSJunLin Chen     }
2194031514fbSJunLin Chen 
21952b9c1dfeSEd Tanous     bool userSelf = (username == req.session->username);
21962b9c1dfeSEd Tanous 
2197e9cc5172SEd Tanous     Privileges effectiveUserPrivileges =
21983e72c202SNinad Palsule         redfish::getUserPrivileges(*req.session);
2199e9cc5172SEd Tanous     Privileges configureUsers = {"ConfigureUsers"};
2200e9cc5172SEd Tanous     bool userHasConfigureUsers =
2201e9cc5172SEd Tanous         effectiveUserPrivileges.isSupersetOf(configureUsers);
2202e9cc5172SEd Tanous     if (userHasConfigureUsers)
2203e9cc5172SEd Tanous     {
2204e9cc5172SEd Tanous         // Users with ConfigureUsers can modify for all users
220558345856SAbhishek Patel         if (!json_util::readJsonPatch(
220658345856SAbhishek Patel                 req, asyncResp->res, "UserName", newUserName, "Password",
220758345856SAbhishek Patel                 password, "RoleId", roleId, "Enabled", enabled, "Locked",
220858345856SAbhishek Patel                 locked, "AccountTypes", accountTypes))
2209a840879dSEd Tanous         {
2210a840879dSEd Tanous             return;
2211a840879dSEd Tanous         }
2212e9cc5172SEd Tanous     }
2213e9cc5172SEd Tanous     else
2214900f9497SJoseph Reynolds     {
2215e9cc5172SEd Tanous         // ConfigureSelf accounts can only modify their own account
221658345856SAbhishek Patel         if (!userSelf)
2217900f9497SJoseph Reynolds         {
2218900f9497SJoseph Reynolds             messages::insufficientPrivilege(asyncResp->res);
2219900f9497SJoseph Reynolds             return;
2220900f9497SJoseph Reynolds         }
2221031514fbSJunLin Chen 
2222e9cc5172SEd Tanous         // ConfigureSelf accounts can only modify their password
22231ef4c342SEd Tanous         if (!json_util::readJsonPatch(req, asyncResp->res, "Password",
22241ef4c342SEd Tanous                                       password))
2225e9cc5172SEd Tanous         {
2226e9cc5172SEd Tanous             return;
2227e9cc5172SEd Tanous         }
2228900f9497SJoseph Reynolds     }
2229900f9497SJoseph Reynolds 
223066b5ca76Sjayaprakash Mutyala     // if user name is not provided in the patch method or if it
22316c51eab1SEd Tanous     // matches the user name in the URI, then we are treating it as
22326c51eab1SEd Tanous     // updating user properties other then username. If username
22336c51eab1SEd Tanous     // provided doesn't match the URI, then we are treating this as
22346c51eab1SEd Tanous     // user rename request.
223566b5ca76Sjayaprakash Mutyala     if (!newUserName || (newUserName.value() == username))
2236a840879dSEd Tanous     {
22371ef4c342SEd Tanous         updateUserProperties(asyncResp, username, password, enabled, roleId,
2238e518ef32SRavi Teja                              locked, accountTypes, userSelf, req.session);
223984e12cb7SAppaRao Puli         return;
224084e12cb7SAppaRao Puli     }
224184e12cb7SAppaRao Puli     crow::connections::systemBus->async_method_call(
22426c51eab1SEd Tanous         [asyncResp, username, password(std::move(password)),
22431ef4c342SEd Tanous          roleId(std::move(roleId)), enabled, newUser{std::string(*newUserName)},
2244e518ef32SRavi Teja          locked, userSelf, req, accountTypes(std::move(accountTypes))](
2245e81de512SEd Tanous             const boost::system::error_code& ec, sdbusplus::message_t& m) {
224684e12cb7SAppaRao Puli             if (ec)
224784e12cb7SAppaRao Puli             {
2248002d39b4SEd Tanous                 userErrorMessageHandler(m.get_error(), asyncResp, newUser,
2249002d39b4SEd Tanous                                         username);
2250a840879dSEd Tanous                 return;
2251a840879dSEd Tanous             }
2252a840879dSEd Tanous 
2253002d39b4SEd Tanous             updateUserProperties(asyncResp, newUser, password, enabled, roleId,
2254e518ef32SRavi Teja                                  locked, accountTypes, userSelf, req.session);
225584e12cb7SAppaRao Puli         },
22561ef4c342SEd Tanous         "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
225784e12cb7SAppaRao Puli         "xyz.openbmc_project.User.Manager", "RenameUser", username,
225884e12cb7SAppaRao Puli         *newUserName);
22591ef4c342SEd Tanous }
22601ef4c342SEd Tanous 
22611ef4c342SEd Tanous inline void requestAccountServiceRoutes(App& app)
22621ef4c342SEd Tanous {
22631ef4c342SEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/AccountService/")
22644c7d4d33SEd Tanous         .privileges(redfish::privileges::headAccountService)
22654c7d4d33SEd Tanous         .methods(boost::beast::http::verb::head)(
22664c7d4d33SEd Tanous             std::bind_front(handleAccountServiceHead, std::ref(app)));
22674c7d4d33SEd Tanous 
22684c7d4d33SEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/AccountService/")
22691ef4c342SEd Tanous         .privileges(redfish::privileges::getAccountService)
22701ef4c342SEd Tanous         .methods(boost::beast::http::verb::get)(
22711ef4c342SEd Tanous             std::bind_front(handleAccountServiceGet, std::ref(app)));
22721ef4c342SEd Tanous 
22731ef4c342SEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/AccountService/")
22741ef4c342SEd Tanous         .privileges(redfish::privileges::patchAccountService)
22751ef4c342SEd Tanous         .methods(boost::beast::http::verb::patch)(
22761ef4c342SEd Tanous             std::bind_front(handleAccountServicePatch, std::ref(app)));
22771ef4c342SEd Tanous 
22781aa375b8SEd Tanous     BMCWEB_ROUTE(
22791aa375b8SEd Tanous         app,
2280*e9f12014SEd Tanous         "/redfish/v1/AccountService/MultiFactorAuth/ClientCertificate/Certificates/")
22811aa375b8SEd Tanous         .privileges(redfish::privileges::headCertificateCollection)
22821aa375b8SEd Tanous         .methods(boost::beast::http::verb::head)(std::bind_front(
22831aa375b8SEd Tanous             handleAccountServiceClientCertificatesHead, std::ref(app)));
22841aa375b8SEd Tanous 
22851aa375b8SEd Tanous     BMCWEB_ROUTE(
22861aa375b8SEd Tanous         app,
2287*e9f12014SEd Tanous         "/redfish/v1/AccountService/MultiFactorAuth/ClientCertificate/Certificates/")
22881aa375b8SEd Tanous         .privileges(redfish::privileges::getCertificateCollection)
22891aa375b8SEd Tanous         .methods(boost::beast::http::verb::get)(std::bind_front(
22901aa375b8SEd Tanous             handleAccountServiceClientCertificatesGet, std::ref(app)));
22911aa375b8SEd Tanous 
22921aa375b8SEd Tanous     BMCWEB_ROUTE(
22931aa375b8SEd Tanous         app,
2294*e9f12014SEd Tanous         "/redfish/v1/AccountService/MultiFactorAuth/ClientCertificate/Certificates/<str>/")
22951aa375b8SEd Tanous         .privileges(redfish::privileges::headCertificate)
22961aa375b8SEd Tanous         .methods(boost::beast::http::verb::head)(std::bind_front(
22971aa375b8SEd Tanous             handleAccountServiceClientCertificatesInstanceHead, std::ref(app)));
22981aa375b8SEd Tanous 
22991aa375b8SEd Tanous     BMCWEB_ROUTE(
23001aa375b8SEd Tanous         app,
23011aa375b8SEd Tanous         "/redfish/v1/AccountService/MultiFactorAuth/ClientCertificate/Certificates/<str>/")
23021aa375b8SEd Tanous         .privileges(redfish::privileges::getCertificate)
23031aa375b8SEd Tanous         .methods(boost::beast::http::verb::get)(std::bind_front(
23041aa375b8SEd Tanous             handleAccountServiceClientCertificatesInstanceGet, std::ref(app)));
23051aa375b8SEd Tanous 
23061ef4c342SEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/")
23074c7d4d33SEd Tanous         .privileges(redfish::privileges::headManagerAccountCollection)
23084c7d4d33SEd Tanous         .methods(boost::beast::http::verb::head)(
23094c7d4d33SEd Tanous             std::bind_front(handleAccountCollectionHead, std::ref(app)));
23104c7d4d33SEd Tanous 
23114c7d4d33SEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/")
23121ef4c342SEd Tanous         .privileges(redfish::privileges::getManagerAccountCollection)
23131ef4c342SEd Tanous         .methods(boost::beast::http::verb::get)(
23141ef4c342SEd Tanous             std::bind_front(handleAccountCollectionGet, std::ref(app)));
23151ef4c342SEd Tanous 
23161ef4c342SEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/")
23171ef4c342SEd Tanous         .privileges(redfish::privileges::postManagerAccountCollection)
23181ef4c342SEd Tanous         .methods(boost::beast::http::verb::post)(
23191ef4c342SEd Tanous             std::bind_front(handleAccountCollectionPost, std::ref(app)));
23201ef4c342SEd Tanous 
23211ef4c342SEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/<str>/")
23224c7d4d33SEd Tanous         .privileges(redfish::privileges::headManagerAccount)
23234c7d4d33SEd Tanous         .methods(boost::beast::http::verb::head)(
23244c7d4d33SEd Tanous             std::bind_front(handleAccountHead, std::ref(app)));
23254c7d4d33SEd Tanous 
23264c7d4d33SEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/<str>/")
23271ef4c342SEd Tanous         .privileges(redfish::privileges::getManagerAccount)
23281ef4c342SEd Tanous         .methods(boost::beast::http::verb::get)(
23291ef4c342SEd Tanous             std::bind_front(handleAccountGet, std::ref(app)));
23301ef4c342SEd Tanous 
23311ef4c342SEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/<str>/")
23321ef4c342SEd Tanous         // TODO this privilege should be using the generated endpoints, but
23331ef4c342SEd Tanous         // because of the special handling of ConfigureSelf, it's not able to
23341ef4c342SEd Tanous         // yet
23351ef4c342SEd Tanous         .privileges({{"ConfigureUsers"}, {"ConfigureSelf"}})
23361ef4c342SEd Tanous         .methods(boost::beast::http::verb::patch)(
23371ef4c342SEd Tanous             std::bind_front(handleAccountPatch, std::ref(app)));
233884e12cb7SAppaRao Puli 
23396c51eab1SEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/<str>/")
2340ed398213SEd Tanous         .privileges(redfish::privileges::deleteManagerAccount)
23416c51eab1SEd Tanous         .methods(boost::beast::http::verb::delete_)(
234220fc307fSGunnar Mills             std::bind_front(handleAccountDelete, std::ref(app)));
234306e086d9SEd Tanous }
234488d16c9aSLewanczyk, Dawid 
234588d16c9aSLewanczyk, Dawid } // namespace redfish
2346