xref: /openbmc/bmcweb/features/redfish/lib/account_service.hpp (revision 492ec93abb4fc7e12acd9abd3b1d4d115531d2c1)
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 
420afc474aeSMyung Bae             if (!json_util::readJsonObject( //
421afc474aeSMyung Bae                     *obj, asyncResp->res, //
422afc474aeSMyung Bae                     "LocalRole", localRole, //
423afc474aeSMyung Bae                     "RemoteGroup", remoteGroup //
424afc474aeSMyung Bae                     ))
42506785244SRatan Gupta             {
42606785244SRatan Gupta                 continue;
42706785244SRatan Gupta             }
42806785244SRatan Gupta 
42906785244SRatan Gupta             // Update existing RoleMapping Object
43006785244SRatan Gupta             if (index < roleMapObjData.size())
43106785244SRatan Gupta             {
43262598e31SEd Tanous                 BMCWEB_LOG_DEBUG("Update Role Map Object");
43306785244SRatan Gupta                 // If "RemoteGroup" info is provided
43406785244SRatan Gupta                 if (remoteGroup)
43506785244SRatan Gupta                 {
436d02aad39SEd Tanous                     setDbusProperty(
437e93abac6SGinu George                         asyncResp,
438d02aad39SEd Tanous                         std::format("RemoteRoleMapping/{}/RemoteGroup", index),
439e93abac6SGinu George                         ldapDbusService, roleMapObjData[index].first,
440e93abac6SGinu George                         "xyz.openbmc_project.User.PrivilegeMapperEntry",
441e93abac6SGinu George                         "GroupName", *remoteGroup);
44206785244SRatan Gupta                 }
44306785244SRatan Gupta 
44406785244SRatan Gupta                 // If "LocalRole" info is provided
44506785244SRatan Gupta                 if (localRole)
44606785244SRatan Gupta                 {
4476d0b80beSRavi Teja                     std::string priv = getPrivilegeFromRoleId(*localRole);
4486d0b80beSRavi Teja                     if (priv.empty())
4496d0b80beSRavi Teja                     {
4506d0b80beSRavi Teja                         messages::propertyValueNotInList(
4516d0b80beSRavi Teja                             asyncResp->res, *localRole,
4526d0b80beSRavi Teja                             std::format("RemoteRoleMapping/{}/LocalRole",
4536d0b80beSRavi Teja                                         index));
4546d0b80beSRavi Teja                         return;
4556d0b80beSRavi Teja                     }
456d02aad39SEd Tanous                     setDbusProperty(
457e93abac6SGinu George                         asyncResp,
458d02aad39SEd Tanous                         std::format("RemoteRoleMapping/{}/LocalRole", index),
459e93abac6SGinu George                         ldapDbusService, roleMapObjData[index].first,
460e93abac6SGinu George                         "xyz.openbmc_project.User.PrivilegeMapperEntry",
4616d0b80beSRavi Teja                         "Privilege", priv);
46206785244SRatan Gupta                 }
46306785244SRatan Gupta             }
46406785244SRatan Gupta             // Create a new RoleMapping Object.
46506785244SRatan Gupta             else
46606785244SRatan Gupta             {
46762598e31SEd Tanous                 BMCWEB_LOG_DEBUG(
46862598e31SEd Tanous                     "setRoleMappingProperties: Creating new Object");
469bd79bce8SPatrick Williams                 std::string pathString =
470bd79bce8SPatrick Williams                     "RemoteRoleMapping/" + std::to_string(index);
47106785244SRatan Gupta 
47206785244SRatan Gupta                 if (!localRole)
47306785244SRatan Gupta                 {
47406785244SRatan Gupta                     messages::propertyMissing(asyncResp->res,
47506785244SRatan Gupta                                               pathString + "/LocalRole");
47606785244SRatan Gupta                     continue;
47706785244SRatan Gupta                 }
47806785244SRatan Gupta                 if (!remoteGroup)
47906785244SRatan Gupta                 {
48006785244SRatan Gupta                     messages::propertyMissing(asyncResp->res,
48106785244SRatan Gupta                                               pathString + "/RemoteGroup");
48206785244SRatan Gupta                     continue;
48306785244SRatan Gupta                 }
48406785244SRatan Gupta 
48506785244SRatan Gupta                 std::string dbusObjectPath;
48606785244SRatan Gupta                 if (serverType == "ActiveDirectory")
48706785244SRatan Gupta                 {
4882c70f800SEd Tanous                     dbusObjectPath = adConfigObject;
48906785244SRatan Gupta                 }
49006785244SRatan Gupta                 else if (serverType == "LDAP")
49106785244SRatan Gupta                 {
49223a21a1cSEd Tanous                     dbusObjectPath = ldapConfigObjectName;
49306785244SRatan Gupta                 }
49406785244SRatan Gupta 
49562598e31SEd Tanous                 BMCWEB_LOG_DEBUG("Remote Group={},LocalRole={}", *remoteGroup,
49662598e31SEd Tanous                                  *localRole);
49706785244SRatan Gupta 
49806785244SRatan Gupta                 crow::connections::systemBus->async_method_call(
499271584abSEd Tanous                     [asyncResp, serverType, localRole,
5005e7e2dc5SEd Tanous                      remoteGroup](const boost::system::error_code& ec) {
50106785244SRatan Gupta                         if (ec)
50206785244SRatan Gupta                         {
50362598e31SEd Tanous                             BMCWEB_LOG_ERROR("DBUS response error: {}", ec);
50406785244SRatan Gupta                             messages::internalError(asyncResp->res);
50506785244SRatan Gupta                             return;
50606785244SRatan Gupta                         }
50706785244SRatan Gupta                         nlohmann::json& remoteRoleJson =
50806785244SRatan Gupta                             asyncResp->res
50906785244SRatan Gupta                                 .jsonValue[serverType]["RemoteRoleMapping"];
5101476687dSEd Tanous                         nlohmann::json::object_t roleMapEntry;
5111476687dSEd Tanous                         roleMapEntry["LocalRole"] = *localRole;
5121476687dSEd Tanous                         roleMapEntry["RemoteGroup"] = *remoteGroup;
513b2ba3072SPatrick Williams                         remoteRoleJson.emplace_back(std::move(roleMapEntry));
51406785244SRatan Gupta                     },
51506785244SRatan Gupta                     ldapDbusService, dbusObjectPath, ldapPrivMapperInterface,
5163174e4dfSEd Tanous                     "Create", *remoteGroup,
51706785244SRatan Gupta                     getPrivilegeFromRoleId(std::move(*localRole)));
51806785244SRatan Gupta             }
51906785244SRatan Gupta         }
52006785244SRatan Gupta     }
52106785244SRatan Gupta }
52206785244SRatan Gupta 
52306785244SRatan Gupta /**
5246973a582SRatan Gupta  * Function that retrieves all properties for LDAP config object
5256973a582SRatan Gupta  * into JSON
5266973a582SRatan Gupta  */
5276973a582SRatan Gupta template <typename CallbackFunc>
528bd79bce8SPatrick Williams inline void
529bd79bce8SPatrick Williams     getLDAPConfigData(const std::string& ldapType, CallbackFunc&& callback)
5306973a582SRatan Gupta {
5312b73119cSGeorge Liu     constexpr std::array<std::string_view, 2> interfaces = {
5322b73119cSGeorge Liu         ldapEnableInterface, ldapConfigInterface};
53354fc587aSNagaraju Goruganti 
5342b73119cSGeorge Liu     dbus::utility::getDbusObject(
5352b73119cSGeorge Liu         ldapConfigObjectName, interfaces,
5368cb2c024SEd Tanous         [callback = std::forward<CallbackFunc>(callback),
537c1019828SEd Tanous          ldapType](const boost::system::error_code& ec,
538c1019828SEd Tanous                    const dbus::utility::MapperGetObject& resp) mutable {
53954fc587aSNagaraju Goruganti             if (ec || resp.empty())
54054fc587aSNagaraju Goruganti             {
541bf2ddedeSCarson Labrado                 BMCWEB_LOG_WARNING(
542bd79bce8SPatrick Williams                     "DBUS response error during getting of service name: {}",
543bd79bce8SPatrick Williams                     ec);
54423a21a1cSEd Tanous                 LDAPConfigData empty{};
54523a21a1cSEd Tanous                 callback(false, empty, ldapType);
54654fc587aSNagaraju Goruganti                 return;
54754fc587aSNagaraju Goruganti             }
54854fc587aSNagaraju Goruganti             std::string service = resp.begin()->first;
5495eb468daSGeorge Liu             sdbusplus::message::object_path path(ldapRootObject);
5505eb468daSGeorge Liu             dbus::utility::getManagedObjects(
5515eb468daSGeorge Liu                 service, path,
552bd79bce8SPatrick Williams                 [callback, ldapType](const boost::system::error_code& ec2,
553bd79bce8SPatrick Williams                                      const dbus::utility::ManagedObjectType&
554bd79bce8SPatrick Williams                                          ldapObjects) mutable {
5556973a582SRatan Gupta                     LDAPConfigData confData{};
5568b24275dSEd Tanous                     if (ec2)
5576973a582SRatan Gupta                     {
558ab828d7cSRatan Gupta                         callback(false, confData, ldapType);
559bf2ddedeSCarson Labrado                         BMCWEB_LOG_WARNING("D-Bus responses error: {}", ec2);
5606973a582SRatan Gupta                         return;
5616973a582SRatan Gupta                     }
562ab828d7cSRatan Gupta 
563ab828d7cSRatan Gupta                     std::string ldapDbusType;
56454fc587aSNagaraju Goruganti                     std::string searchString;
56554fc587aSNagaraju Goruganti 
566ab828d7cSRatan Gupta                     if (ldapType == "LDAP")
567ab828d7cSRatan Gupta                     {
5680fda0f12SGeorge Liu                         ldapDbusType =
5690fda0f12SGeorge Liu                             "xyz.openbmc_project.User.Ldap.Config.Type.OpenLdap";
57054fc587aSNagaraju Goruganti                         searchString = "openldap";
571ab828d7cSRatan Gupta                     }
572ab828d7cSRatan Gupta                     else if (ldapType == "ActiveDirectory")
573ab828d7cSRatan Gupta                     {
57454fc587aSNagaraju Goruganti                         ldapDbusType =
5750fda0f12SGeorge Liu                             "xyz.openbmc_project.User.Ldap.Config.Type.ActiveDirectory";
57654fc587aSNagaraju Goruganti                         searchString = "active_directory";
577ab828d7cSRatan Gupta                     }
578ab828d7cSRatan Gupta                     else
579ab828d7cSRatan Gupta                     {
580bd79bce8SPatrick Williams                         BMCWEB_LOG_ERROR(
581bd79bce8SPatrick Williams                             "Can't get the DbusType for the given type={}",
58262598e31SEd Tanous                             ldapType);
583ab828d7cSRatan Gupta                         callback(false, confData, ldapType);
584ab828d7cSRatan Gupta                         return;
585ab828d7cSRatan Gupta                     }
586ab828d7cSRatan Gupta 
587ab828d7cSRatan Gupta                     std::string ldapEnableInterfaceStr = ldapEnableInterface;
588ab828d7cSRatan Gupta                     std::string ldapConfigInterfaceStr = ldapConfigInterface;
589ab828d7cSRatan Gupta 
5906973a582SRatan Gupta                     for (const auto& object : ldapObjects)
5916973a582SRatan Gupta                     {
59254fc587aSNagaraju Goruganti                         // let's find the object whose ldap type is equal to the
59354fc587aSNagaraju Goruganti                         // given type
594bd79bce8SPatrick Williams                         if (object.first.str.find(searchString) ==
595bd79bce8SPatrick Williams                             std::string::npos)
5966973a582SRatan Gupta                         {
597ab828d7cSRatan Gupta                             continue;
598ab828d7cSRatan Gupta                         }
599ab828d7cSRatan Gupta 
6006973a582SRatan Gupta                         for (const auto& interface : object.second)
6016973a582SRatan Gupta                         {
6026973a582SRatan Gupta                             if (interface.first == ldapEnableInterfaceStr)
6036973a582SRatan Gupta                             {
6046973a582SRatan Gupta                                 // rest of the properties are string.
6056973a582SRatan Gupta                                 for (const auto& property : interface.second)
6066973a582SRatan Gupta                                 {
6076973a582SRatan Gupta                                     if (property.first == "Enabled")
6086973a582SRatan Gupta                                     {
6096973a582SRatan Gupta                                         const bool* value =
6106973a582SRatan Gupta                                             std::get_if<bool>(&property.second);
6116973a582SRatan Gupta                                         if (value == nullptr)
6126973a582SRatan Gupta                                         {
6136973a582SRatan Gupta                                             continue;
6146973a582SRatan Gupta                                         }
6156973a582SRatan Gupta                                         confData.serviceEnabled = *value;
6166973a582SRatan Gupta                                         break;
6176973a582SRatan Gupta                                     }
6186973a582SRatan Gupta                                 }
6196973a582SRatan Gupta                             }
6206973a582SRatan Gupta                             else if (interface.first == ldapConfigInterfaceStr)
6216973a582SRatan Gupta                             {
6226973a582SRatan Gupta                                 for (const auto& property : interface.second)
6236973a582SRatan Gupta                                 {
624271584abSEd Tanous                                     const std::string* strValue =
625bd79bce8SPatrick Williams                                         std::get_if<std::string>(
626bd79bce8SPatrick Williams                                             &property.second);
627271584abSEd Tanous                                     if (strValue == nullptr)
6286973a582SRatan Gupta                                     {
6296973a582SRatan Gupta                                         continue;
6306973a582SRatan Gupta                                     }
6316973a582SRatan Gupta                                     if (property.first == "LDAPServerURI")
6326973a582SRatan Gupta                                     {
633271584abSEd Tanous                                         confData.uri = *strValue;
6346973a582SRatan Gupta                                     }
6356973a582SRatan Gupta                                     else if (property.first == "LDAPBindDN")
6366973a582SRatan Gupta                                     {
637271584abSEd Tanous                                         confData.bindDN = *strValue;
6386973a582SRatan Gupta                                     }
6396973a582SRatan Gupta                                     else if (property.first == "LDAPBaseDN")
6406973a582SRatan Gupta                                     {
641271584abSEd Tanous                                         confData.baseDN = *strValue;
6426973a582SRatan Gupta                                     }
643bd79bce8SPatrick Williams                                     else if (property.first ==
644bd79bce8SPatrick Williams                                              "LDAPSearchScope")
6456973a582SRatan Gupta                                     {
646271584abSEd Tanous                                         confData.searchScope = *strValue;
6476973a582SRatan Gupta                                     }
648bd79bce8SPatrick Williams                                     else if (property.first ==
649bd79bce8SPatrick Williams                                              "GroupNameAttribute")
6506973a582SRatan Gupta                                     {
651271584abSEd Tanous                                         confData.groupAttribute = *strValue;
6526973a582SRatan Gupta                                     }
653bd79bce8SPatrick Williams                                     else if (property.first ==
654bd79bce8SPatrick Williams                                              "UserNameAttribute")
6556973a582SRatan Gupta                                     {
656271584abSEd Tanous                                         confData.userNameAttribute = *strValue;
6576973a582SRatan Gupta                                     }
65854fc587aSNagaraju Goruganti                                     else if (property.first == "LDAPType")
659ab828d7cSRatan Gupta                                     {
660271584abSEd Tanous                                         confData.serverType = *strValue;
66154fc587aSNagaraju Goruganti                                     }
66254fc587aSNagaraju Goruganti                                 }
66354fc587aSNagaraju Goruganti                             }
664bd79bce8SPatrick Williams                             else if (
665bd79bce8SPatrick Williams                                 interface.first ==
6660fda0f12SGeorge Liu                                 "xyz.openbmc_project.User.PrivilegeMapperEntry")
66754fc587aSNagaraju Goruganti                             {
66854fc587aSNagaraju Goruganti                                 LDAPRoleMapData roleMapData{};
66954fc587aSNagaraju Goruganti                                 for (const auto& property : interface.second)
67054fc587aSNagaraju Goruganti                                 {
671271584abSEd Tanous                                     const std::string* strValue =
672bd79bce8SPatrick Williams                                         std::get_if<std::string>(
673bd79bce8SPatrick Williams                                             &property.second);
67454fc587aSNagaraju Goruganti 
675271584abSEd Tanous                                     if (strValue == nullptr)
67654fc587aSNagaraju Goruganti                                     {
67754fc587aSNagaraju Goruganti                                         continue;
67854fc587aSNagaraju Goruganti                                     }
67954fc587aSNagaraju Goruganti 
68054fc587aSNagaraju Goruganti                                     if (property.first == "GroupName")
68154fc587aSNagaraju Goruganti                                     {
682271584abSEd Tanous                                         roleMapData.groupName = *strValue;
68354fc587aSNagaraju Goruganti                                     }
68454fc587aSNagaraju Goruganti                                     else if (property.first == "Privilege")
68554fc587aSNagaraju Goruganti                                     {
686271584abSEd Tanous                                         roleMapData.privilege = *strValue;
68754fc587aSNagaraju Goruganti                                     }
68854fc587aSNagaraju Goruganti                                 }
68954fc587aSNagaraju Goruganti 
690bd79bce8SPatrick Williams                                 confData.groupRoleList.emplace_back(
691bd79bce8SPatrick Williams                                     object.first.str, roleMapData);
69254fc587aSNagaraju Goruganti                             }
69354fc587aSNagaraju Goruganti                         }
69454fc587aSNagaraju Goruganti                     }
695ab828d7cSRatan Gupta                     callback(true, confData, ldapType);
6965eb468daSGeorge Liu                 });
6972b73119cSGeorge Liu         });
6986973a582SRatan Gupta }
6996973a582SRatan Gupta 
7008a07d286SRatan Gupta /**
7018a07d286SRatan Gupta  * @brief updates the LDAP server address and updates the
7028a07d286SRatan Gupta           json response with the new value.
7038a07d286SRatan Gupta  * @param serviceAddressList address to be updated.
7048a07d286SRatan Gupta  * @param asyncResp pointer to the JSON response
7058a07d286SRatan Gupta  * @param ldapServerElementName Type of LDAP
7068a07d286SRatan Gupta  server(openLDAP/ActiveDirectory)
7078a07d286SRatan Gupta  */
7088a07d286SRatan Gupta 
7094f48d5f6SEd Tanous inline void handleServiceAddressPatch(
7108a07d286SRatan Gupta     const std::vector<std::string>& serviceAddressList,
7118d1b46d7Szhanghch05     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
7128a07d286SRatan Gupta     const std::string& ldapServerElementName,
7138a07d286SRatan Gupta     const std::string& ldapConfigObject)
7148a07d286SRatan Gupta {
715e93abac6SGinu George     setDbusProperty(asyncResp, ldapServerElementName + "/ServiceAddress",
716e93abac6SGinu George                     ldapDbusService, ldapConfigObject, ldapConfigInterface,
717e93abac6SGinu George                     "LDAPServerURI", serviceAddressList.front());
7188a07d286SRatan Gupta }
7198a07d286SRatan Gupta /**
7208a07d286SRatan Gupta  * @brief updates the LDAP Bind DN and updates the
7218a07d286SRatan Gupta           json response with the new value.
7228a07d286SRatan Gupta  * @param username name of the user which needs to be updated.
7238a07d286SRatan Gupta  * @param asyncResp pointer to the JSON response
7248a07d286SRatan Gupta  * @param ldapServerElementName Type of LDAP
7258a07d286SRatan Gupta  server(openLDAP/ActiveDirectory)
7268a07d286SRatan Gupta  */
7278a07d286SRatan Gupta 
7284f48d5f6SEd Tanous inline void
7294f48d5f6SEd Tanous     handleUserNamePatch(const std::string& username,
7308d1b46d7Szhanghch05                         const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
7318a07d286SRatan Gupta                         const std::string& ldapServerElementName,
7328a07d286SRatan Gupta                         const std::string& ldapConfigObject)
7338a07d286SRatan Gupta {
734e93abac6SGinu George     setDbusProperty(asyncResp,
735d02aad39SEd Tanous                     ldapServerElementName + "/Authentication/Username",
736e93abac6SGinu George                     ldapDbusService, ldapConfigObject, ldapConfigInterface,
737e93abac6SGinu George                     "LDAPBindDN", username);
7388a07d286SRatan Gupta }
7398a07d286SRatan Gupta 
7408a07d286SRatan Gupta /**
7418a07d286SRatan Gupta  * @brief updates the LDAP password
7428a07d286SRatan Gupta  * @param password : ldap password which needs to be updated.
7438a07d286SRatan Gupta  * @param asyncResp pointer to the JSON response
7448a07d286SRatan Gupta  * @param ldapServerElementName Type of LDAP
7458a07d286SRatan Gupta  *        server(openLDAP/ActiveDirectory)
7468a07d286SRatan Gupta  */
7478a07d286SRatan Gupta 
7484f48d5f6SEd Tanous inline void
7494f48d5f6SEd Tanous     handlePasswordPatch(const std::string& password,
7508d1b46d7Szhanghch05                         const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
7518a07d286SRatan Gupta                         const std::string& ldapServerElementName,
7528a07d286SRatan Gupta                         const std::string& ldapConfigObject)
7538a07d286SRatan Gupta {
754e93abac6SGinu George     setDbusProperty(asyncResp,
755d02aad39SEd Tanous                     ldapServerElementName + "/Authentication/Password",
756e93abac6SGinu George                     ldapDbusService, ldapConfigObject, ldapConfigInterface,
757e93abac6SGinu George                     "LDAPBindDNPassword", password);
7588a07d286SRatan Gupta }
7598a07d286SRatan Gupta 
7608a07d286SRatan Gupta /**
7618a07d286SRatan Gupta  * @brief updates the LDAP BaseDN and updates the
7628a07d286SRatan Gupta           json response with the new value.
7638a07d286SRatan Gupta  * @param baseDNList baseDN list which needs to be updated.
7648a07d286SRatan Gupta  * @param asyncResp pointer to the JSON response
7658a07d286SRatan Gupta  * @param ldapServerElementName Type of LDAP
7668a07d286SRatan Gupta  server(openLDAP/ActiveDirectory)
7678a07d286SRatan Gupta  */
7688a07d286SRatan Gupta 
7694f48d5f6SEd Tanous inline void
7704f48d5f6SEd Tanous     handleBaseDNPatch(const std::vector<std::string>& baseDNList,
7718d1b46d7Szhanghch05                       const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
7728a07d286SRatan Gupta                       const std::string& ldapServerElementName,
7738a07d286SRatan Gupta                       const std::string& ldapConfigObject)
7748a07d286SRatan Gupta {
775e93abac6SGinu George     setDbusProperty(asyncResp,
776d02aad39SEd Tanous                     ldapServerElementName +
777d02aad39SEd Tanous                         "/LDAPService/SearchSettings/BaseDistinguishedNames",
778e93abac6SGinu George                     ldapDbusService, ldapConfigObject, ldapConfigInterface,
779e93abac6SGinu George                     "LDAPBaseDN", baseDNList.front());
7808a07d286SRatan Gupta }
7818a07d286SRatan Gupta /**
7828a07d286SRatan Gupta  * @brief updates the LDAP user name attribute and updates the
7838a07d286SRatan Gupta           json response with the new value.
7848a07d286SRatan Gupta  * @param userNameAttribute attribute to be updated.
7858a07d286SRatan Gupta  * @param asyncResp pointer to the JSON response
7868a07d286SRatan Gupta  * @param ldapServerElementName Type of LDAP
7878a07d286SRatan Gupta  server(openLDAP/ActiveDirectory)
7888a07d286SRatan Gupta  */
7898a07d286SRatan Gupta 
790bd79bce8SPatrick Williams inline void handleUserNameAttrPatch(
791bd79bce8SPatrick Williams     const std::string& userNameAttribute,
7928d1b46d7Szhanghch05     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
7938a07d286SRatan Gupta     const std::string& ldapServerElementName,
7948a07d286SRatan Gupta     const std::string& ldapConfigObject)
7958a07d286SRatan Gupta {
796bd79bce8SPatrick Williams     setDbusProperty(
797bd79bce8SPatrick Williams         asyncResp,
798bd79bce8SPatrick Williams         ldapServerElementName + "LDAPService/SearchSettings/UsernameAttribute",
799e93abac6SGinu George         ldapDbusService, ldapConfigObject, ldapConfigInterface,
800e93abac6SGinu George         "UserNameAttribute", userNameAttribute);
8018a07d286SRatan Gupta }
8028a07d286SRatan Gupta /**
8038a07d286SRatan Gupta  * @brief updates the LDAP group attribute and updates the
8048a07d286SRatan Gupta           json response with the new value.
8058a07d286SRatan Gupta  * @param groupsAttribute attribute to be updated.
8068a07d286SRatan Gupta  * @param asyncResp pointer to the JSON response
8078a07d286SRatan Gupta  * @param ldapServerElementName Type of LDAP
8088a07d286SRatan Gupta  server(openLDAP/ActiveDirectory)
8098a07d286SRatan Gupta  */
8108a07d286SRatan Gupta 
8114f48d5f6SEd Tanous inline void handleGroupNameAttrPatch(
8128d1b46d7Szhanghch05     const std::string& groupsAttribute,
8138d1b46d7Szhanghch05     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
8148a07d286SRatan Gupta     const std::string& ldapServerElementName,
8158a07d286SRatan Gupta     const std::string& ldapConfigObject)
8168a07d286SRatan Gupta {
817bd79bce8SPatrick Williams     setDbusProperty(
818bd79bce8SPatrick Williams         asyncResp,
819bd79bce8SPatrick Williams         ldapServerElementName + "/LDAPService/SearchSettings/GroupsAttribute",
820e93abac6SGinu George         ldapDbusService, ldapConfigObject, ldapConfigInterface,
821e93abac6SGinu George         "GroupNameAttribute", groupsAttribute);
8228a07d286SRatan Gupta }
8238a07d286SRatan Gupta /**
8248a07d286SRatan Gupta  * @brief updates the LDAP service enable and updates the
8258a07d286SRatan Gupta           json response with the new value.
8268a07d286SRatan Gupta  * @param input JSON data.
8278a07d286SRatan Gupta  * @param asyncResp pointer to the JSON response
8288a07d286SRatan Gupta  * @param ldapServerElementName Type of LDAP
8298a07d286SRatan Gupta  server(openLDAP/ActiveDirectory)
8308a07d286SRatan Gupta  */
8318a07d286SRatan Gupta 
8324f48d5f6SEd Tanous inline void handleServiceEnablePatch(
8336c51eab1SEd Tanous     bool serviceEnabled, const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
8348a07d286SRatan Gupta     const std::string& ldapServerElementName,
8358a07d286SRatan Gupta     const std::string& ldapConfigObject)
8368a07d286SRatan Gupta {
837e93abac6SGinu George     setDbusProperty(asyncResp, ldapServerElementName + "/ServiceEnabled",
838e93abac6SGinu George                     ldapDbusService, ldapConfigObject, ldapEnableInterface,
839e93abac6SGinu George                     "Enabled", serviceEnabled);
8408a07d286SRatan Gupta }
8418a07d286SRatan Gupta 
842c1019828SEd Tanous struct AuthMethods
84378158631SZbigniew Kurzynski {
84478158631SZbigniew Kurzynski     std::optional<bool> basicAuth;
84578158631SZbigniew Kurzynski     std::optional<bool> cookie;
84678158631SZbigniew Kurzynski     std::optional<bool> sessionToken;
84778158631SZbigniew Kurzynski     std::optional<bool> xToken;
848501f1e58SZbigniew Kurzynski     std::optional<bool> tls;
849c1019828SEd Tanous };
85078158631SZbigniew Kurzynski 
851c1019828SEd Tanous inline void
852c1019828SEd Tanous     handleAuthMethodsPatch(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
853c1019828SEd Tanous                            const AuthMethods& auth)
85478158631SZbigniew Kurzynski {
855c1019828SEd Tanous     persistent_data::AuthConfigMethods& authMethodsConfig =
85652cc112dSEd Tanous         persistent_data::SessionStore::getInstance().getAuthMethodsConfig();
85778158631SZbigniew Kurzynski 
858c1019828SEd Tanous     if (auth.basicAuth)
85978158631SZbigniew Kurzynski     {
86025b54dbaSEd Tanous         if constexpr (!BMCWEB_BASIC_AUTH)
86125b54dbaSEd Tanous         {
862f16f6263SAlan Kuo             messages::actionNotSupported(
8630fda0f12SGeorge Liu                 asyncResp->res,
8640fda0f12SGeorge Liu                 "Setting BasicAuth when basic-auth feature is disabled");
865f16f6263SAlan Kuo             return;
86625b54dbaSEd Tanous         }
86725b54dbaSEd Tanous 
868c1019828SEd Tanous         authMethodsConfig.basic = *auth.basicAuth;
86978158631SZbigniew Kurzynski     }
87078158631SZbigniew Kurzynski 
871c1019828SEd Tanous     if (auth.cookie)
87278158631SZbigniew Kurzynski     {
87325b54dbaSEd Tanous         if constexpr (!BMCWEB_COOKIE_AUTH)
87425b54dbaSEd Tanous         {
8750fda0f12SGeorge Liu             messages::actionNotSupported(
8760fda0f12SGeorge Liu                 asyncResp->res,
8770fda0f12SGeorge Liu                 "Setting Cookie when cookie-auth feature is disabled");
878f16f6263SAlan Kuo             return;
87925b54dbaSEd Tanous         }
880c1019828SEd Tanous         authMethodsConfig.cookie = *auth.cookie;
88178158631SZbigniew Kurzynski     }
88278158631SZbigniew Kurzynski 
883c1019828SEd Tanous     if (auth.sessionToken)
88478158631SZbigniew Kurzynski     {
88525b54dbaSEd Tanous         if constexpr (!BMCWEB_SESSION_AUTH)
88625b54dbaSEd Tanous         {
887f16f6263SAlan Kuo             messages::actionNotSupported(
8880fda0f12SGeorge Liu                 asyncResp->res,
8890fda0f12SGeorge Liu                 "Setting SessionToken when session-auth feature is disabled");
890f16f6263SAlan Kuo             return;
89125b54dbaSEd Tanous         }
892c1019828SEd Tanous         authMethodsConfig.sessionToken = *auth.sessionToken;
89378158631SZbigniew Kurzynski     }
89478158631SZbigniew Kurzynski 
895c1019828SEd Tanous     if (auth.xToken)
89678158631SZbigniew Kurzynski     {
89725b54dbaSEd Tanous         if constexpr (!BMCWEB_XTOKEN_AUTH)
89825b54dbaSEd Tanous         {
8990fda0f12SGeorge Liu             messages::actionNotSupported(
9000fda0f12SGeorge Liu                 asyncResp->res,
9010fda0f12SGeorge Liu                 "Setting XToken when xtoken-auth feature is disabled");
902f16f6263SAlan Kuo             return;
90325b54dbaSEd Tanous         }
904c1019828SEd Tanous         authMethodsConfig.xtoken = *auth.xToken;
90578158631SZbigniew Kurzynski     }
90678158631SZbigniew Kurzynski 
907c1019828SEd Tanous     if (auth.tls)
908501f1e58SZbigniew Kurzynski     {
90925b54dbaSEd Tanous         if constexpr (!BMCWEB_MUTUAL_TLS_AUTH)
91025b54dbaSEd Tanous         {
9110fda0f12SGeorge Liu             messages::actionNotSupported(
9120fda0f12SGeorge Liu                 asyncResp->res,
9130fda0f12SGeorge Liu                 "Setting TLS when mutual-tls-auth feature is disabled");
914f16f6263SAlan Kuo             return;
91525b54dbaSEd Tanous         }
916c1019828SEd Tanous         authMethodsConfig.tls = *auth.tls;
917501f1e58SZbigniew Kurzynski     }
918501f1e58SZbigniew Kurzynski 
91978158631SZbigniew Kurzynski     if (!authMethodsConfig.basic && !authMethodsConfig.cookie &&
920501f1e58SZbigniew Kurzynski         !authMethodsConfig.sessionToken && !authMethodsConfig.xtoken &&
921501f1e58SZbigniew Kurzynski         !authMethodsConfig.tls)
92278158631SZbigniew Kurzynski     {
92378158631SZbigniew Kurzynski         // Do not allow user to disable everything
92478158631SZbigniew Kurzynski         messages::actionNotSupported(asyncResp->res,
92578158631SZbigniew Kurzynski                                      "of disabling all available methods");
92678158631SZbigniew Kurzynski         return;
92778158631SZbigniew Kurzynski     }
92878158631SZbigniew Kurzynski 
92952cc112dSEd Tanous     persistent_data::SessionStore::getInstance().updateAuthMethodsConfig(
93052cc112dSEd Tanous         authMethodsConfig);
93178158631SZbigniew Kurzynski     // Save configuration immediately
93252cc112dSEd Tanous     persistent_data::getConfig().writeData();
93378158631SZbigniew Kurzynski 
93478158631SZbigniew Kurzynski     messages::success(asyncResp->res);
93578158631SZbigniew Kurzynski }
93678158631SZbigniew Kurzynski 
9378a07d286SRatan Gupta /**
9388a07d286SRatan Gupta  * @brief Get the required values from the given JSON, validates the
9398a07d286SRatan Gupta  *        value and create the LDAP config object.
9408a07d286SRatan Gupta  * @param input JSON data
9418a07d286SRatan Gupta  * @param asyncResp pointer to the JSON response
9428a07d286SRatan Gupta  * @param serverType Type of LDAP server(openLDAP/ActiveDirectory)
9438a07d286SRatan Gupta  */
9448a07d286SRatan Gupta 
94510cb44f3SEd Tanous struct LdapPatchParams
94610cb44f3SEd Tanous {
94710cb44f3SEd Tanous     std::optional<std::string> authType;
94810cb44f3SEd Tanous     std::optional<std::vector<std::string>> serviceAddressList;
94910cb44f3SEd Tanous     std::optional<bool> serviceEnabled;
95010cb44f3SEd Tanous     std::optional<std::vector<std::string>> baseDNList;
95110cb44f3SEd Tanous     std::optional<std::string> userNameAttribute;
95210cb44f3SEd Tanous     std::optional<std::string> groupsAttribute;
95310cb44f3SEd Tanous     std::optional<std::string> userName;
95410cb44f3SEd Tanous     std::optional<std::string> password;
95510cb44f3SEd Tanous     std::optional<
95610cb44f3SEd Tanous         std::vector<std::variant<nlohmann::json::object_t, std::nullptr_t>>>
95710cb44f3SEd Tanous         remoteRoleMapData;
95810cb44f3SEd Tanous };
95910cb44f3SEd Tanous 
96010cb44f3SEd Tanous inline void handleLDAPPatch(LdapPatchParams&& input,
9618d1b46d7Szhanghch05                             const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
9628a07d286SRatan Gupta                             const std::string& serverType)
9638a07d286SRatan Gupta {
964eb2bbe56SRatan Gupta     std::string dbusObjectPath;
965eb2bbe56SRatan Gupta     if (serverType == "ActiveDirectory")
966eb2bbe56SRatan Gupta     {
9672c70f800SEd Tanous         dbusObjectPath = adConfigObject;
968eb2bbe56SRatan Gupta     }
969eb2bbe56SRatan Gupta     else if (serverType == "LDAP")
970eb2bbe56SRatan Gupta     {
97123a21a1cSEd Tanous         dbusObjectPath = ldapConfigObjectName;
972eb2bbe56SRatan Gupta     }
973cb13a392SEd Tanous     else
974cb13a392SEd Tanous     {
97510cb44f3SEd Tanous         BMCWEB_LOG_ERROR("serverType wasn't AD or LDAP but was {}????",
97610cb44f3SEd Tanous                          serverType);
977cb13a392SEd Tanous         return;
978cb13a392SEd Tanous     }
979eb2bbe56SRatan Gupta 
98010cb44f3SEd Tanous     if (input.authType && *input.authType != "UsernameAndPassword")
9818a07d286SRatan Gupta     {
98210cb44f3SEd Tanous         messages::propertyValueNotInList(asyncResp->res, *input.authType,
983c1019828SEd Tanous                                          "AuthenticationType");
984c1019828SEd Tanous         return;
9858a07d286SRatan Gupta     }
986c1019828SEd Tanous 
98710cb44f3SEd Tanous     if (input.serviceAddressList)
9888a07d286SRatan Gupta     {
98910cb44f3SEd Tanous         if (input.serviceAddressList->empty())
9908a07d286SRatan Gupta         {
991e2616cc5SEd Tanous             messages::propertyValueNotInList(
99210cb44f3SEd Tanous                 asyncResp->res, *input.serviceAddressList, "ServiceAddress");
9938a07d286SRatan Gupta             return;
9948a07d286SRatan Gupta         }
9958a07d286SRatan Gupta     }
99610cb44f3SEd Tanous     if (input.baseDNList)
9978a07d286SRatan Gupta     {
99810cb44f3SEd Tanous         if (input.baseDNList->empty())
9998a07d286SRatan Gupta         {
100010cb44f3SEd Tanous             messages::propertyValueNotInList(asyncResp->res, *input.baseDNList,
10018a07d286SRatan Gupta                                              "BaseDistinguishedNames");
10028a07d286SRatan Gupta             return;
10038a07d286SRatan Gupta         }
10048a07d286SRatan Gupta     }
10058a07d286SRatan Gupta 
10068a07d286SRatan Gupta     // nothing to update, then return
100710cb44f3SEd Tanous     if (!input.userName && !input.password && !input.serviceAddressList &&
100810cb44f3SEd Tanous         !input.baseDNList && !input.userNameAttribute &&
100910cb44f3SEd Tanous         !input.groupsAttribute && !input.serviceEnabled &&
101010cb44f3SEd Tanous         !input.remoteRoleMapData)
10118a07d286SRatan Gupta     {
10128a07d286SRatan Gupta         return;
10138a07d286SRatan Gupta     }
10148a07d286SRatan Gupta 
10158a07d286SRatan Gupta     // Get the existing resource first then keep modifying
10168a07d286SRatan Gupta     // whenever any property gets updated.
1017bd79bce8SPatrick Williams     getLDAPConfigData(serverType, [asyncResp, input = std::move(input),
101810cb44f3SEd Tanous                                    dbusObjectPath = std::move(dbusObjectPath)](
1019bd79bce8SPatrick Williams                                       bool success,
1020bd79bce8SPatrick Williams                                       const LDAPConfigData& confData,
1021c1019828SEd Tanous                                       const std::string& serverT) mutable {
10228a07d286SRatan Gupta         if (!success)
10238a07d286SRatan Gupta         {
10248a07d286SRatan Gupta             messages::internalError(asyncResp->res);
10258a07d286SRatan Gupta             return;
10268a07d286SRatan Gupta         }
10276c51eab1SEd Tanous         parseLDAPConfigData(asyncResp->res.jsonValue, confData, serverT);
10288a07d286SRatan Gupta         if (confData.serviceEnabled)
10298a07d286SRatan Gupta         {
10308a07d286SRatan Gupta             // Disable the service first and update the rest of
10318a07d286SRatan Gupta             // the properties.
10326c51eab1SEd Tanous             handleServiceEnablePatch(false, asyncResp, serverT, dbusObjectPath);
10338a07d286SRatan Gupta         }
10348a07d286SRatan Gupta 
103510cb44f3SEd Tanous         if (input.serviceAddressList)
10368a07d286SRatan Gupta         {
103710cb44f3SEd Tanous             handleServiceAddressPatch(*input.serviceAddressList, asyncResp,
103810cb44f3SEd Tanous                                       serverT, dbusObjectPath);
103910cb44f3SEd Tanous         }
104010cb44f3SEd Tanous         if (input.userName)
104110cb44f3SEd Tanous         {
104210cb44f3SEd Tanous             handleUserNamePatch(*input.userName, asyncResp, serverT,
10436c51eab1SEd Tanous                                 dbusObjectPath);
10448a07d286SRatan Gupta         }
104510cb44f3SEd Tanous         if (input.password)
10468a07d286SRatan Gupta         {
104710cb44f3SEd Tanous             handlePasswordPatch(*input.password, asyncResp, serverT,
104810cb44f3SEd Tanous                                 dbusObjectPath);
10498a07d286SRatan Gupta         }
10508a07d286SRatan Gupta 
105110cb44f3SEd Tanous         if (input.baseDNList)
10528a07d286SRatan Gupta         {
105310cb44f3SEd Tanous             handleBaseDNPatch(*input.baseDNList, asyncResp, serverT,
10546c51eab1SEd Tanous                               dbusObjectPath);
10558a07d286SRatan Gupta         }
105610cb44f3SEd Tanous         if (input.userNameAttribute)
10578a07d286SRatan Gupta         {
105810cb44f3SEd Tanous             handleUserNameAttrPatch(*input.userNameAttribute, asyncResp,
105910cb44f3SEd Tanous                                     serverT, dbusObjectPath);
106010cb44f3SEd Tanous         }
106110cb44f3SEd Tanous         if (input.groupsAttribute)
106210cb44f3SEd Tanous         {
106310cb44f3SEd Tanous             handleGroupNameAttrPatch(*input.groupsAttribute, asyncResp, serverT,
10646c51eab1SEd Tanous                                      dbusObjectPath);
10658a07d286SRatan Gupta         }
106610cb44f3SEd Tanous         if (input.serviceEnabled)
10678a07d286SRatan Gupta         {
10688a07d286SRatan Gupta             // if user has given the value as true then enable
10698a07d286SRatan Gupta             // the service. if user has given false then no-op
10708a07d286SRatan Gupta             // as service is already stopped.
107110cb44f3SEd Tanous             if (*input.serviceEnabled)
10728a07d286SRatan Gupta             {
107310cb44f3SEd Tanous                 handleServiceEnablePatch(*input.serviceEnabled, asyncResp,
107410cb44f3SEd Tanous                                          serverT, dbusObjectPath);
10758a07d286SRatan Gupta             }
10768a07d286SRatan Gupta         }
10778a07d286SRatan Gupta         else
10788a07d286SRatan Gupta         {
10798a07d286SRatan Gupta             // if user has not given the service enabled value
10808a07d286SRatan Gupta             // then revert it to the same state as it was
10818a07d286SRatan Gupta             // before.
10828a07d286SRatan Gupta             handleServiceEnablePatch(confData.serviceEnabled, asyncResp,
108323a21a1cSEd Tanous                                      serverT, dbusObjectPath);
10848a07d286SRatan Gupta         }
108506785244SRatan Gupta 
108610cb44f3SEd Tanous         if (input.remoteRoleMapData)
108706785244SRatan Gupta         {
10886c51eab1SEd Tanous             handleRoleMapPatch(asyncResp, confData.groupRoleList, serverT,
108910cb44f3SEd Tanous                                *input.remoteRoleMapData);
109006785244SRatan Gupta         }
10918a07d286SRatan Gupta     });
10928a07d286SRatan Gupta }
1093d4b5443fSEd Tanous 
1094*492ec93aSEd Tanous struct UserUpdateParams
10951abe55efSEd Tanous {
1096*492ec93aSEd Tanous     std::string username;
1097*492ec93aSEd Tanous     std::optional<std::string> password;
1098*492ec93aSEd Tanous     std::optional<bool> enabled;
1099*492ec93aSEd Tanous     std::optional<std::string> roleId;
1100*492ec93aSEd Tanous     std::optional<bool> locked;
1101*492ec93aSEd Tanous     std::optional<std::vector<std::string>> accountTypes;
1102*492ec93aSEd Tanous     bool userSelf;
1103*492ec93aSEd Tanous     std::shared_ptr<persistent_data::UserSession> session;
1104*492ec93aSEd Tanous     std::string dbusObjectPath;
1105*492ec93aSEd Tanous };
11066c51eab1SEd Tanous 
1107*492ec93aSEd Tanous inline void
1108*492ec93aSEd Tanous     afterVerifyUserExists(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1109*492ec93aSEd Tanous                           const UserUpdateParams& params, int rc)
1110*492ec93aSEd Tanous {
1111e662eae8SEd Tanous     if (rc <= 0)
11126c51eab1SEd Tanous     {
1113d8a5d5d8SJiaqing Zhao         messages::resourceNotFound(asyncResp->res, "ManagerAccount",
1114*492ec93aSEd Tanous                                    params.username);
11156c51eab1SEd Tanous         return;
11166c51eab1SEd Tanous     }
11176c51eab1SEd Tanous 
1118*492ec93aSEd Tanous     if (params.password)
11196c51eab1SEd Tanous     {
1120*492ec93aSEd Tanous         int retval = pamUpdatePassword(params.username, *params.password);
11216c51eab1SEd Tanous 
11226c51eab1SEd Tanous         if (retval == PAM_USER_UNKNOWN)
11236c51eab1SEd Tanous         {
1124d8a5d5d8SJiaqing Zhao             messages::resourceNotFound(asyncResp->res, "ManagerAccount",
1125*492ec93aSEd Tanous                                        params.username);
11266c51eab1SEd Tanous         }
11276c51eab1SEd Tanous         else if (retval == PAM_AUTHTOK_ERR)
11286c51eab1SEd Tanous         {
11296c51eab1SEd Tanous             // If password is invalid
11309bd80831SJason M. Bills             messages::propertyValueFormatError(asyncResp->res, nullptr,
11319bd80831SJason M. Bills                                                "Password");
113262598e31SEd Tanous             BMCWEB_LOG_ERROR("pamUpdatePassword Failed");
11336c51eab1SEd Tanous         }
11346c51eab1SEd Tanous         else if (retval != PAM_SUCCESS)
11356c51eab1SEd Tanous         {
11366c51eab1SEd Tanous             messages::internalError(asyncResp->res);
11376c51eab1SEd Tanous             return;
11386c51eab1SEd Tanous         }
1139e7b1b62bSEd Tanous         else
1140e7b1b62bSEd Tanous         {
1141bd79bce8SPatrick Williams             // Remove existing sessions of the user when password
1142bd79bce8SPatrick Williams             // changed
1143e518ef32SRavi Teja             persistent_data::SessionStore::getInstance()
1144*492ec93aSEd Tanous                 .removeSessionsByUsernameExceptSession(params.username,
1145*492ec93aSEd Tanous                                                        params.session);
1146e7b1b62bSEd Tanous             messages::success(asyncResp->res);
1147e7b1b62bSEd Tanous         }
11486c51eab1SEd Tanous     }
11496c51eab1SEd Tanous 
1150*492ec93aSEd Tanous     if (params.enabled)
11516c51eab1SEd Tanous     {
1152bd79bce8SPatrick Williams         setDbusProperty(
1153bd79bce8SPatrick Williams             asyncResp, "Enabled", "xyz.openbmc_project.User.Manager",
1154*492ec93aSEd Tanous             params.dbusObjectPath, "xyz.openbmc_project.User.Attributes",
1155*492ec93aSEd Tanous             "UserEnabled", *params.enabled);
11566c51eab1SEd Tanous     }
11576c51eab1SEd Tanous 
1158*492ec93aSEd Tanous     if (params.roleId)
11596c51eab1SEd Tanous     {
1160*492ec93aSEd Tanous         std::string priv = getPrivilegeFromRoleId(*params.roleId);
11616c51eab1SEd Tanous         if (priv.empty())
11626c51eab1SEd Tanous         {
1163*492ec93aSEd Tanous             messages::propertyValueNotInList(asyncResp->res, true, "Locked");
11646c51eab1SEd Tanous             return;
11656c51eab1SEd Tanous         }
1166*492ec93aSEd Tanous         setDbusProperty(asyncResp, "RoleId", "xyz.openbmc_project.User.Manager",
1167*492ec93aSEd Tanous                         params.dbusObjectPath,
1168*492ec93aSEd Tanous                         "xyz.openbmc_project.User.Attributes", "UserPrivilege",
1169*492ec93aSEd Tanous                         priv);
11706c51eab1SEd Tanous     }
11716c51eab1SEd Tanous 
1172*492ec93aSEd Tanous     if (params.locked)
11736c51eab1SEd Tanous     {
11746c51eab1SEd Tanous         // admin can unlock the account which is locked by
11756c51eab1SEd Tanous         // successive authentication failures but admin should
11766c51eab1SEd Tanous         // not be allowed to lock an account.
1177*492ec93aSEd Tanous         if (*params.locked)
11786c51eab1SEd Tanous         {
1179*492ec93aSEd Tanous             messages::propertyValueNotInList(asyncResp->res, "true", "Locked");
11806c51eab1SEd Tanous             return;
11816c51eab1SEd Tanous         }
1182*492ec93aSEd Tanous         setDbusProperty(asyncResp, "Locked", "xyz.openbmc_project.User.Manager",
1183*492ec93aSEd Tanous                         params.dbusObjectPath,
1184*492ec93aSEd Tanous                         "xyz.openbmc_project.User.Attributes",
1185*492ec93aSEd Tanous                         "UserLockedForFailedAttempt", *params.locked);
11866c51eab1SEd Tanous     }
118758345856SAbhishek Patel 
1188*492ec93aSEd Tanous     if (params.accountTypes)
118958345856SAbhishek Patel     {
1190*492ec93aSEd Tanous         patchAccountTypes(*params.accountTypes, asyncResp,
1191*492ec93aSEd Tanous                           params.dbusObjectPath, params.userSelf);
119258345856SAbhishek Patel     }
1193*492ec93aSEd Tanous }
1194*492ec93aSEd Tanous 
1195*492ec93aSEd Tanous inline void updateUserProperties(
1196*492ec93aSEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1197*492ec93aSEd Tanous     const std::string& username, const std::optional<std::string>& password,
1198*492ec93aSEd Tanous     const std::optional<bool>& enabled,
1199*492ec93aSEd Tanous     const std::optional<std::string>& roleId, const std::optional<bool>& locked,
1200*492ec93aSEd Tanous     const std::optional<std::vector<std::string>>& accountTypes, bool userSelf,
1201*492ec93aSEd Tanous     const std::shared_ptr<persistent_data::UserSession>& session)
1202*492ec93aSEd Tanous {
1203*492ec93aSEd Tanous     sdbusplus::message::object_path tempObjPath(rootUserDbusPath);
1204*492ec93aSEd Tanous     tempObjPath /= username;
1205*492ec93aSEd Tanous     std::string dbusObjectPath(tempObjPath);
1206*492ec93aSEd Tanous 
1207*492ec93aSEd Tanous     UserUpdateParams params{username, password, enabled,
1208*492ec93aSEd Tanous                             roleId,   locked,   accountTypes,
1209*492ec93aSEd Tanous                             userSelf, session,  dbusObjectPath};
1210*492ec93aSEd Tanous 
1211*492ec93aSEd Tanous     dbus::utility::checkDbusPathExists(
1212*492ec93aSEd Tanous         dbusObjectPath,
1213*492ec93aSEd Tanous         std::bind_front(afterVerifyUserExists, asyncResp, std::move(params)));
12146c51eab1SEd Tanous }
12156c51eab1SEd Tanous 
12164c7d4d33SEd Tanous inline void handleAccountServiceHead(
12174c7d4d33SEd Tanous     App& app, const crow::Request& req,
12181ef4c342SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
12196c51eab1SEd Tanous {
12203ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
122145ca1b86SEd Tanous     {
122245ca1b86SEd Tanous         return;
122345ca1b86SEd Tanous     }
12244c7d4d33SEd Tanous     asyncResp->res.addHeader(
12254c7d4d33SEd Tanous         boost::beast::http::field::link,
12264c7d4d33SEd Tanous         "</redfish/v1/JsonSchemas/AccountService/AccountService.json>; rel=describedby");
12274c7d4d33SEd Tanous }
12284c7d4d33SEd Tanous 
12294c7d4d33SEd Tanous inline void
12301aa375b8SEd Tanous     getClientCertificates(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
12311aa375b8SEd Tanous                           const nlohmann::json::json_pointer& keyLocation)
12321aa375b8SEd Tanous {
12331aa375b8SEd Tanous     boost::urls::url url(
12341aa375b8SEd Tanous         "/redfish/v1/AccountService/MultiFactorAuth/ClientCertificate/Certificates");
12351aa375b8SEd Tanous     std::array<std::string_view, 1> interfaces = {
12361aa375b8SEd Tanous         "xyz.openbmc_project.Certs.Certificate"};
12371aa375b8SEd Tanous     std::string path = "/xyz/openbmc_project/certs/authority/truststore";
12381aa375b8SEd Tanous 
12391aa375b8SEd Tanous     collection_util::getCollectionToKey(asyncResp, url, interfaces, path,
12401aa375b8SEd Tanous                                         keyLocation);
12411aa375b8SEd Tanous }
12421aa375b8SEd Tanous 
12431aa375b8SEd Tanous inline void handleAccountServiceClientCertificatesInstanceHead(
12441aa375b8SEd Tanous     App& app, const crow::Request& req,
12451aa375b8SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
12461aa375b8SEd Tanous     const std::string& /*id*/)
12471aa375b8SEd Tanous {
12481aa375b8SEd Tanous     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
12491aa375b8SEd Tanous     {
12501aa375b8SEd Tanous         return;
12511aa375b8SEd Tanous     }
12521aa375b8SEd Tanous 
12531aa375b8SEd Tanous     asyncResp->res.addHeader(
12541aa375b8SEd Tanous         boost::beast::http::field::link,
12551aa375b8SEd Tanous         "</redfish/v1/JsonSchemas/Certificate/Certificate.json>; rel=describedby");
12561aa375b8SEd Tanous }
12571aa375b8SEd Tanous 
12581aa375b8SEd Tanous inline void handleAccountServiceClientCertificatesInstanceGet(
12591aa375b8SEd Tanous     App& app, const crow::Request& req,
12601aa375b8SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id)
12611aa375b8SEd Tanous {
12621aa375b8SEd Tanous     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
12631aa375b8SEd Tanous     {
12641aa375b8SEd Tanous         return;
12651aa375b8SEd Tanous     }
12661aa375b8SEd Tanous     BMCWEB_LOG_DEBUG("ClientCertificate Certificate ID={}", id);
12671aa375b8SEd Tanous     const boost::urls::url certURL = boost::urls::format(
12681aa375b8SEd Tanous         "/redfish/v1/AccountService/MultiFactorAuth/ClientCertificate/Certificates/{}",
12691aa375b8SEd Tanous         id);
12701aa375b8SEd Tanous     std::string objPath =
12711aa375b8SEd Tanous         sdbusplus::message::object_path(certs::authorityObjectPath) / id;
12721aa375b8SEd Tanous     getCertificateProperties(
12731aa375b8SEd Tanous         asyncResp, objPath,
12741aa375b8SEd Tanous         "xyz.openbmc_project.Certs.Manager.Authority.Truststore", id, certURL,
12751aa375b8SEd Tanous         "Client Certificate");
12761aa375b8SEd Tanous }
12771aa375b8SEd Tanous 
12781aa375b8SEd Tanous inline void handleAccountServiceClientCertificatesHead(
12791aa375b8SEd Tanous     App& app, const crow::Request& req,
12801aa375b8SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
12811aa375b8SEd Tanous {
12821aa375b8SEd Tanous     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
12831aa375b8SEd Tanous     {
12841aa375b8SEd Tanous         return;
12851aa375b8SEd Tanous     }
12861aa375b8SEd Tanous 
12871aa375b8SEd Tanous     asyncResp->res.addHeader(
12881aa375b8SEd Tanous         boost::beast::http::field::link,
12891aa375b8SEd Tanous         "</redfish/v1/JsonSchemas/CertificateCollection/CertificateCollection.json>; rel=describedby");
12901aa375b8SEd Tanous }
12911aa375b8SEd Tanous 
12921aa375b8SEd Tanous inline void handleAccountServiceClientCertificatesGet(
12931aa375b8SEd Tanous     App& app, const crow::Request& req,
12941aa375b8SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
12951aa375b8SEd Tanous {
12961aa375b8SEd Tanous     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
12971aa375b8SEd Tanous     {
12981aa375b8SEd Tanous         return;
12991aa375b8SEd Tanous     }
13001aa375b8SEd Tanous     getClientCertificates(asyncResp, "/Members"_json_pointer);
13011aa375b8SEd Tanous }
13021aa375b8SEd Tanous 
13033ce3688aSEd Tanous using account_service::CertificateMappingAttribute;
13043ce3688aSEd Tanous using persistent_data::MTLSCommonNameParseMode;
13053ce3688aSEd Tanous inline CertificateMappingAttribute
13063ce3688aSEd Tanous     getCertificateMapping(MTLSCommonNameParseMode parse)
13073ce3688aSEd Tanous {
13083ce3688aSEd Tanous     switch (parse)
13093ce3688aSEd Tanous     {
13103ce3688aSEd Tanous         case MTLSCommonNameParseMode::CommonName:
13113ce3688aSEd Tanous         {
13123ce3688aSEd Tanous             return CertificateMappingAttribute::CommonName;
13133ce3688aSEd Tanous         }
13143ce3688aSEd Tanous         break;
13153ce3688aSEd Tanous         case MTLSCommonNameParseMode::Whole:
13163ce3688aSEd Tanous         {
13173ce3688aSEd Tanous             return CertificateMappingAttribute::Whole;
13183ce3688aSEd Tanous         }
13193ce3688aSEd Tanous         break;
13203ce3688aSEd Tanous         case MTLSCommonNameParseMode::UserPrincipalName:
13213ce3688aSEd Tanous         {
13223ce3688aSEd Tanous             return CertificateMappingAttribute::UserPrincipalName;
13233ce3688aSEd Tanous         }
13243ce3688aSEd Tanous         break;
13253ce3688aSEd Tanous 
13263ce3688aSEd Tanous         case MTLSCommonNameParseMode::Meta:
13273ce3688aSEd Tanous         {
13283ce3688aSEd Tanous             if constexpr (BMCWEB_META_TLS_COMMON_NAME_PARSING)
13293ce3688aSEd Tanous             {
13303ce3688aSEd Tanous                 return CertificateMappingAttribute::CommonName;
13313ce3688aSEd Tanous             }
13323ce3688aSEd Tanous         }
13333ce3688aSEd Tanous         break;
13343ce3688aSEd Tanous         default:
13353ce3688aSEd Tanous         {
13363ce3688aSEd Tanous             return CertificateMappingAttribute::Invalid;
13373ce3688aSEd Tanous         }
13383ce3688aSEd Tanous         break;
13393ce3688aSEd Tanous     }
13403ce3688aSEd Tanous }
13413ce3688aSEd Tanous 
13421aa375b8SEd Tanous inline void
13434c7d4d33SEd Tanous     handleAccountServiceGet(App& app, const crow::Request& req,
13444c7d4d33SEd Tanous                             const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
13454c7d4d33SEd Tanous {
1346afd369c6SJiaqing Zhao     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1347afd369c6SJiaqing Zhao     {
1348afd369c6SJiaqing Zhao         return;
1349afd369c6SJiaqing Zhao     }
13503e72c202SNinad Palsule 
13513e72c202SNinad Palsule     if (req.session == nullptr)
13523e72c202SNinad Palsule     {
13533e72c202SNinad Palsule         messages::internalError(asyncResp->res);
13543e72c202SNinad Palsule         return;
13553e72c202SNinad Palsule     }
13563e72c202SNinad Palsule 
1357c1019828SEd Tanous     const persistent_data::AuthConfigMethods& authMethodsConfig =
1358c1019828SEd Tanous         persistent_data::SessionStore::getInstance().getAuthMethodsConfig();
1359c1019828SEd Tanous 
1360afd369c6SJiaqing Zhao     asyncResp->res.addHeader(
1361afd369c6SJiaqing Zhao         boost::beast::http::field::link,
1362afd369c6SJiaqing Zhao         "</redfish/v1/JsonSchemas/AccountService/AccountService.json>; rel=describedby");
1363afd369c6SJiaqing Zhao 
13641476687dSEd Tanous     nlohmann::json& json = asyncResp->res.jsonValue;
13651476687dSEd Tanous     json["@odata.id"] = "/redfish/v1/AccountService";
1366482a69e7SRavi Teja     json["@odata.type"] = "#AccountService.v1_15_0.AccountService";
13671476687dSEd Tanous     json["Id"] = "AccountService";
13681476687dSEd Tanous     json["Name"] = "Account Service";
13691476687dSEd Tanous     json["Description"] = "Account Service";
13701476687dSEd Tanous     json["ServiceEnabled"] = true;
13711476687dSEd Tanous     json["MaxPasswordLength"] = 20;
13721ef4c342SEd Tanous     json["Accounts"]["@odata.id"] = "/redfish/v1/AccountService/Accounts";
13731476687dSEd Tanous     json["Roles"]["@odata.id"] = "/redfish/v1/AccountService/Roles";
1374482a69e7SRavi Teja     json["HTTPBasicAuth"] = authMethodsConfig.basic
1375482a69e7SRavi Teja                                 ? account_service::BasicAuthState::Enabled
1376482a69e7SRavi Teja                                 : account_service::BasicAuthState::Disabled;
1377482a69e7SRavi Teja 
1378482a69e7SRavi Teja     nlohmann::json::array_t allowed;
1379482a69e7SRavi Teja     allowed.emplace_back(account_service::BasicAuthState::Enabled);
1380482a69e7SRavi Teja     allowed.emplace_back(account_service::BasicAuthState::Disabled);
1381482a69e7SRavi Teja     json["HTTPBasicAuth@AllowableValues"] = std::move(allowed);
1382482a69e7SRavi Teja 
13831aa375b8SEd Tanous     nlohmann::json::object_t clientCertificate;
13841aa375b8SEd Tanous     clientCertificate["Enabled"] = authMethodsConfig.tls;
13853281bcf1SEd Tanous     clientCertificate["RespondToUnauthenticatedClients"] =
13863281bcf1SEd Tanous         !authMethodsConfig.tlsStrict;
13873ce3688aSEd Tanous 
13883ce3688aSEd Tanous     using account_service::CertificateMappingAttribute;
13893ce3688aSEd Tanous 
13903ce3688aSEd Tanous     CertificateMappingAttribute mapping =
13913ce3688aSEd Tanous         getCertificateMapping(authMethodsConfig.mTLSCommonNameParsingMode);
13923ce3688aSEd Tanous     if (mapping == CertificateMappingAttribute::Invalid)
13933ce3688aSEd Tanous     {
13943ce3688aSEd Tanous         messages::internalError(asyncResp->res);
13953ce3688aSEd Tanous     }
13963ce3688aSEd Tanous     else
13973ce3688aSEd Tanous     {
13983ce3688aSEd Tanous         clientCertificate["CertificateMappingAttribute"] = mapping;
13993ce3688aSEd Tanous     }
14001aa375b8SEd Tanous     nlohmann::json::object_t certificates;
14011aa375b8SEd Tanous     certificates["@odata.id"] =
14021aa375b8SEd Tanous         "/redfish/v1/AccountService/MultiFactorAuth/ClientCertificate/Certificates";
14031aa375b8SEd Tanous     certificates["@odata.type"] =
14041aa375b8SEd Tanous         "#CertificateCollection.CertificateCollection";
14051aa375b8SEd Tanous     clientCertificate["Certificates"] = std::move(certificates);
14061aa375b8SEd Tanous     json["MultiFactorAuth"]["ClientCertificate"] = std::move(clientCertificate);
14071aa375b8SEd Tanous 
14081aa375b8SEd Tanous     getClientCertificates(
14091aa375b8SEd Tanous         asyncResp,
14101aa375b8SEd Tanous         "/MultiFactorAuth/ClientCertificate/Certificates/Members"_json_pointer);
14111aa375b8SEd Tanous 
14121476687dSEd Tanous     json["Oem"]["OpenBMC"]["@odata.type"] =
14135b5574acSEd Tanous         "#OpenBMCAccountService.v1_0_0.AccountService";
14141476687dSEd Tanous     json["Oem"]["OpenBMC"]["@odata.id"] =
14151476687dSEd Tanous         "/redfish/v1/AccountService#/Oem/OpenBMC";
14161476687dSEd Tanous     json["Oem"]["OpenBMC"]["AuthMethods"]["BasicAuth"] =
14171476687dSEd Tanous         authMethodsConfig.basic;
14181476687dSEd Tanous     json["Oem"]["OpenBMC"]["AuthMethods"]["SessionToken"] =
14191476687dSEd Tanous         authMethodsConfig.sessionToken;
14201ef4c342SEd Tanous     json["Oem"]["OpenBMC"]["AuthMethods"]["XToken"] = authMethodsConfig.xtoken;
14211ef4c342SEd Tanous     json["Oem"]["OpenBMC"]["AuthMethods"]["Cookie"] = authMethodsConfig.cookie;
14221ef4c342SEd Tanous     json["Oem"]["OpenBMC"]["AuthMethods"]["TLS"] = authMethodsConfig.tls;
14231476687dSEd Tanous 
14241ef4c342SEd Tanous     // /redfish/v1/AccountService/LDAP/Certificates is something only
14251ef4c342SEd Tanous     // ConfigureManager can access then only display when the user has
14261ef4c342SEd Tanous     // permissions ConfigureManager
142772048780SAbhishek Patel     Privileges effectiveUserPrivileges =
14283e72c202SNinad Palsule         redfish::getUserPrivileges(*req.session);
142972048780SAbhishek Patel 
143072048780SAbhishek Patel     if (isOperationAllowedWithPrivileges({{"ConfigureManager"}},
143172048780SAbhishek Patel                                          effectiveUserPrivileges))
143272048780SAbhishek Patel     {
14331ef4c342SEd Tanous         asyncResp->res.jsonValue["LDAP"]["Certificates"]["@odata.id"] =
14341476687dSEd Tanous             "/redfish/v1/AccountService/LDAP/Certificates";
143572048780SAbhishek Patel     }
1436deae6a78SEd Tanous     dbus::utility::getAllProperties(
1437deae6a78SEd Tanous         "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
1438deae6a78SEd Tanous         "xyz.openbmc_project.User.AccountPolicy",
14395e7e2dc5SEd Tanous         [asyncResp](const boost::system::error_code& ec,
14401ef4c342SEd Tanous                     const dbus::utility::DBusPropertiesMap& propertiesList) {
14413d958bbcSAppaRao Puli             if (ec)
14423d958bbcSAppaRao Puli             {
14433d958bbcSAppaRao Puli                 messages::internalError(asyncResp->res);
14443d958bbcSAppaRao Puli                 return;
14453d958bbcSAppaRao Puli             }
1446d1bde9e5SKrzysztof Grobelny 
144762598e31SEd Tanous             BMCWEB_LOG_DEBUG("Got {} properties for AccountService",
144862598e31SEd Tanous                              propertiesList.size());
1449d1bde9e5SKrzysztof Grobelny 
1450d1bde9e5SKrzysztof Grobelny             const uint8_t* minPasswordLength = nullptr;
1451d1bde9e5SKrzysztof Grobelny             const uint32_t* accountUnlockTimeout = nullptr;
1452d1bde9e5SKrzysztof Grobelny             const uint16_t* maxLoginAttemptBeforeLockout = nullptr;
1453d1bde9e5SKrzysztof Grobelny 
1454d1bde9e5SKrzysztof Grobelny             const bool success = sdbusplus::unpackPropertiesNoThrow(
1455d1bde9e5SKrzysztof Grobelny                 dbus_utils::UnpackErrorPrinter(), propertiesList,
1456d1bde9e5SKrzysztof Grobelny                 "MinPasswordLength", minPasswordLength, "AccountUnlockTimeout",
1457d1bde9e5SKrzysztof Grobelny                 accountUnlockTimeout, "MaxLoginAttemptBeforeLockout",
1458d1bde9e5SKrzysztof Grobelny                 maxLoginAttemptBeforeLockout);
1459d1bde9e5SKrzysztof Grobelny 
1460d1bde9e5SKrzysztof Grobelny             if (!success)
14613d958bbcSAppaRao Puli             {
1462d1bde9e5SKrzysztof Grobelny                 messages::internalError(asyncResp->res);
1463d1bde9e5SKrzysztof Grobelny                 return;
14643d958bbcSAppaRao Puli             }
1465d1bde9e5SKrzysztof Grobelny 
1466d1bde9e5SKrzysztof Grobelny             if (minPasswordLength != nullptr)
14673d958bbcSAppaRao Puli             {
1468bd79bce8SPatrick Williams                 asyncResp->res.jsonValue["MinPasswordLength"] =
1469bd79bce8SPatrick Williams                     *minPasswordLength;
14703d958bbcSAppaRao Puli             }
1471d1bde9e5SKrzysztof Grobelny 
1472d1bde9e5SKrzysztof Grobelny             if (accountUnlockTimeout != nullptr)
14733d958bbcSAppaRao Puli             {
1474d1bde9e5SKrzysztof Grobelny                 asyncResp->res.jsonValue["AccountLockoutDuration"] =
1475d1bde9e5SKrzysztof Grobelny                     *accountUnlockTimeout;
1476d1bde9e5SKrzysztof Grobelny             }
1477d1bde9e5SKrzysztof Grobelny 
1478d1bde9e5SKrzysztof Grobelny             if (maxLoginAttemptBeforeLockout != nullptr)
14793d958bbcSAppaRao Puli             {
1480002d39b4SEd Tanous                 asyncResp->res.jsonValue["AccountLockoutThreshold"] =
1481d1bde9e5SKrzysztof Grobelny                     *maxLoginAttemptBeforeLockout;
14823d958bbcSAppaRao Puli             }
1483d1bde9e5SKrzysztof Grobelny         });
14846973a582SRatan Gupta 
148502cad96eSEd Tanous     auto callback = [asyncResp](bool success, const LDAPConfigData& confData,
1486ab828d7cSRatan Gupta                                 const std::string& ldapType) {
1487cb13a392SEd Tanous         if (!success)
1488cb13a392SEd Tanous         {
1489cb13a392SEd Tanous             return;
1490cb13a392SEd Tanous         }
1491002d39b4SEd Tanous         parseLDAPConfigData(asyncResp->res.jsonValue, confData, ldapType);
1492ab828d7cSRatan Gupta     };
1493ab828d7cSRatan Gupta 
1494ab828d7cSRatan Gupta     getLDAPConfigData("LDAP", callback);
1495ab828d7cSRatan Gupta     getLDAPConfigData("ActiveDirectory", callback);
14961ef4c342SEd Tanous }
14976973a582SRatan Gupta 
1498bd79bce8SPatrick Williams inline void handleCertificateMappingAttributePatch(
1499bd79bce8SPatrick Williams     crow::Response& res, const std::string& certMapAttribute)
15003ce3688aSEd Tanous {
15013ce3688aSEd Tanous     MTLSCommonNameParseMode parseMode =
15023ce3688aSEd Tanous         persistent_data::getMTLSCommonNameParseMode(certMapAttribute);
15033ce3688aSEd Tanous     if (parseMode == MTLSCommonNameParseMode::Invalid)
15043ce3688aSEd Tanous     {
15053ce3688aSEd Tanous         messages::propertyValueNotInList(res, "CertificateMappingAttribute",
15063ce3688aSEd Tanous                                          certMapAttribute);
15073ce3688aSEd Tanous         return;
15083ce3688aSEd Tanous     }
15093ce3688aSEd Tanous 
15103ce3688aSEd Tanous     persistent_data::AuthConfigMethods& authMethodsConfig =
15113ce3688aSEd Tanous         persistent_data::SessionStore::getInstance().getAuthMethodsConfig();
15123ce3688aSEd Tanous     authMethodsConfig.mTLSCommonNameParsingMode = parseMode;
15133ce3688aSEd Tanous }
15143ce3688aSEd Tanous 
15153281bcf1SEd Tanous inline void handleRespondToUnauthenticatedClientsPatch(
15163281bcf1SEd Tanous     App& app, const crow::Request& req, crow::Response& res,
15173281bcf1SEd Tanous     bool respondToUnauthenticatedClients)
15183281bcf1SEd Tanous {
15193281bcf1SEd Tanous     if (req.session != nullptr)
15203281bcf1SEd Tanous     {
15213281bcf1SEd Tanous         // Sanity check.  If the user isn't currently authenticated with mutual
15223281bcf1SEd Tanous         // TLS, they very likely are about to permanently lock themselves out.
15233281bcf1SEd Tanous         // Make sure they're using mutual TLS before allowing locking.
15243281bcf1SEd Tanous         if (req.session->sessionType != persistent_data::SessionType::MutualTLS)
15253281bcf1SEd Tanous         {
15263281bcf1SEd Tanous             messages::propertyValueExternalConflict(
15273281bcf1SEd Tanous                 res,
15283281bcf1SEd Tanous                 "MultiFactorAuth/ClientCertificate/RespondToUnauthenticatedClients",
15293281bcf1SEd Tanous                 respondToUnauthenticatedClients);
15303281bcf1SEd Tanous             return;
15313281bcf1SEd Tanous         }
15323281bcf1SEd Tanous     }
15333281bcf1SEd Tanous 
15343281bcf1SEd Tanous     persistent_data::AuthConfigMethods& authMethodsConfig =
15353281bcf1SEd Tanous         persistent_data::SessionStore::getInstance().getAuthMethodsConfig();
15363281bcf1SEd Tanous 
15373281bcf1SEd Tanous     // Change the settings
15383281bcf1SEd Tanous     authMethodsConfig.tlsStrict = !respondToUnauthenticatedClients;
15393281bcf1SEd Tanous 
15403281bcf1SEd Tanous     // Write settings to disk
15413281bcf1SEd Tanous     persistent_data::getConfig().writeData();
15423281bcf1SEd Tanous 
15433281bcf1SEd Tanous     // Trigger a reload, to apply the new settings to new connections
15443281bcf1SEd Tanous     app.loadCertificate();
15453281bcf1SEd Tanous }
15463281bcf1SEd Tanous 
15471ef4c342SEd Tanous inline void handleAccountServicePatch(
15481ef4c342SEd Tanous     App& app, const crow::Request& req,
15491ef4c342SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
15501ef4c342SEd Tanous {
15513ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
155245ca1b86SEd Tanous     {
155345ca1b86SEd Tanous         return;
155445ca1b86SEd Tanous     }
1555f5ffd806SEd Tanous     std::optional<uint32_t> unlockTimeout;
1556f5ffd806SEd Tanous     std::optional<uint16_t> lockoutThreshold;
1557ef73ad0dSPaul Fertser     std::optional<uint8_t> minPasswordLength;
1558f5ffd806SEd Tanous     std::optional<uint16_t> maxPasswordLength;
155910cb44f3SEd Tanous     LdapPatchParams ldapObject;
15603ce3688aSEd Tanous     std::optional<std::string> certificateMappingAttribute;
15613281bcf1SEd Tanous     std::optional<bool> respondToUnauthenticatedClients;
156210cb44f3SEd Tanous     LdapPatchParams activeDirectoryObject;
1563c1019828SEd Tanous     AuthMethods auth;
1564482a69e7SRavi Teja     std::optional<std::string> httpBasicAuth;
15653ce3688aSEd Tanous 
1566afc474aeSMyung Bae     if (!json_util::readJsonPatch( //
1567afc474aeSMyung Bae             req, asyncResp->res, //
1568afc474aeSMyung Bae             "AccountLockoutDuration", unlockTimeout, //
1569afc474aeSMyung Bae             "AccountLockoutThreshold", lockoutThreshold, //
1570afc474aeSMyung Bae             "ActiveDirectory/Authentication/AuthenticationType",
1571afc474aeSMyung Bae             activeDirectoryObject.authType, //
1572afc474aeSMyung Bae             "ActiveDirectory/Authentication/Password",
1573afc474aeSMyung Bae             activeDirectoryObject.password, //
1574afc474aeSMyung Bae             "ActiveDirectory/Authentication/Username",
1575afc474aeSMyung Bae             activeDirectoryObject.userName, //
1576afc474aeSMyung Bae             "ActiveDirectory/LDAPService/SearchSettings/BaseDistinguishedNames",
1577afc474aeSMyung Bae             activeDirectoryObject.baseDNList, //
1578afc474aeSMyung Bae             "ActiveDirectory/LDAPService/SearchSettings/GroupsAttribute",
1579afc474aeSMyung Bae             activeDirectoryObject.groupsAttribute, //
1580afc474aeSMyung Bae             "ActiveDirectory/LDAPService/SearchSettings/UsernameAttribute",
1581afc474aeSMyung Bae             activeDirectoryObject.userNameAttribute, //
1582afc474aeSMyung Bae             "ActiveDirectory/RemoteRoleMapping",
1583afc474aeSMyung Bae             activeDirectoryObject.remoteRoleMapData, //
1584afc474aeSMyung Bae             "ActiveDirectory/ServiceAddresses",
1585afc474aeSMyung Bae             activeDirectoryObject.serviceAddressList, //
1586afc474aeSMyung Bae             "ActiveDirectory/ServiceEnabled",
1587afc474aeSMyung Bae             activeDirectoryObject.serviceEnabled, //
1588afc474aeSMyung Bae             "HTTPBasicAuth", httpBasicAuth, //
1589afc474aeSMyung Bae             "LDAP/Authentication/AuthenticationType", ldapObject.authType, //
1590afc474aeSMyung Bae             "LDAP/Authentication/Password", ldapObject.password, //
1591afc474aeSMyung Bae             "LDAP/Authentication/Username", ldapObject.userName, //
1592afc474aeSMyung Bae             "LDAP/LDAPService/SearchSettings/BaseDistinguishedNames",
1593afc474aeSMyung Bae             ldapObject.baseDNList, //
1594afc474aeSMyung Bae             "LDAP/LDAPService/SearchSettings/GroupsAttribute",
1595afc474aeSMyung Bae             ldapObject.groupsAttribute, //
1596afc474aeSMyung Bae             "LDAP/LDAPService/SearchSettings/UsernameAttribute",
1597afc474aeSMyung Bae             ldapObject.userNameAttribute, //
1598afc474aeSMyung Bae             "LDAP/RemoteRoleMapping", ldapObject.remoteRoleMapData, //
1599afc474aeSMyung Bae             "LDAP/ServiceAddresses", ldapObject.serviceAddressList, //
1600afc474aeSMyung Bae             "LDAP/ServiceEnabled", ldapObject.serviceEnabled, //
1601afc474aeSMyung Bae             "MaxPasswordLength", maxPasswordLength, //
1602afc474aeSMyung Bae             "MinPasswordLength", minPasswordLength, //
1603afc474aeSMyung Bae             "MultiFactorAuth/ClientCertificate/CertificateMappingAttribute",
1604afc474aeSMyung Bae             certificateMappingAttribute, //
1605afc474aeSMyung Bae             "MultiFactorAuth/ClientCertificate/RespondToUnauthenticatedClients",
1606afc474aeSMyung Bae             respondToUnauthenticatedClients, //
1607afc474aeSMyung Bae             "Oem/OpenBMC/AuthMethods/BasicAuth", auth.basicAuth, //
1608afc474aeSMyung Bae             "Oem/OpenBMC/AuthMethods/Cookie", auth.cookie, //
1609afc474aeSMyung Bae             "Oem/OpenBMC/AuthMethods/SessionToken", auth.sessionToken, //
1610afc474aeSMyung Bae             "Oem/OpenBMC/AuthMethods/TLS", auth.tls, //
1611afc474aeSMyung Bae             "Oem/OpenBMC/AuthMethods/XToken", auth.xToken //
1612afc474aeSMyung Bae             ))
1613f5ffd806SEd Tanous     {
1614f5ffd806SEd Tanous         return;
1615f5ffd806SEd Tanous     }
1616f5ffd806SEd Tanous 
1617482a69e7SRavi Teja     if (httpBasicAuth)
1618482a69e7SRavi Teja     {
1619482a69e7SRavi Teja         if (*httpBasicAuth == "Enabled")
1620482a69e7SRavi Teja         {
1621482a69e7SRavi Teja             auth.basicAuth = true;
1622482a69e7SRavi Teja         }
1623482a69e7SRavi Teja         else if (*httpBasicAuth == "Disabled")
1624482a69e7SRavi Teja         {
1625482a69e7SRavi Teja             auth.basicAuth = false;
1626482a69e7SRavi Teja         }
1627482a69e7SRavi Teja         else
1628482a69e7SRavi Teja         {
1629482a69e7SRavi Teja             messages::propertyValueNotInList(asyncResp->res, "HttpBasicAuth",
1630482a69e7SRavi Teja                                              *httpBasicAuth);
1631482a69e7SRavi Teja         }
1632482a69e7SRavi Teja     }
1633482a69e7SRavi Teja 
16343281bcf1SEd Tanous     if (respondToUnauthenticatedClients)
16353281bcf1SEd Tanous     {
16363281bcf1SEd Tanous         handleRespondToUnauthenticatedClientsPatch(
16373281bcf1SEd Tanous             app, req, asyncResp->res, *respondToUnauthenticatedClients);
16383281bcf1SEd Tanous     }
16393281bcf1SEd Tanous 
16403ce3688aSEd Tanous     if (certificateMappingAttribute)
16413ce3688aSEd Tanous     {
16423ce3688aSEd Tanous         handleCertificateMappingAttributePatch(asyncResp->res,
16433ce3688aSEd Tanous                                                *certificateMappingAttribute);
16443ce3688aSEd Tanous     }
16453ce3688aSEd Tanous 
1646f5ffd806SEd Tanous     if (minPasswordLength)
1647f5ffd806SEd Tanous     {
1648d02aad39SEd Tanous         setDbusProperty(
1649e93abac6SGinu George             asyncResp, "MinPasswordLength", "xyz.openbmc_project.User.Manager",
1650d02aad39SEd Tanous             sdbusplus::message::object_path("/xyz/openbmc_project/user"),
16519ae226faSGeorge Liu             "xyz.openbmc_project.User.AccountPolicy", "MinPasswordLength",
1652e93abac6SGinu George             *minPasswordLength);
1653f5ffd806SEd Tanous     }
1654f5ffd806SEd Tanous 
1655f5ffd806SEd Tanous     if (maxPasswordLength)
1656f5ffd806SEd Tanous     {
16571ef4c342SEd Tanous         messages::propertyNotWritable(asyncResp->res, "MaxPasswordLength");
1658f5ffd806SEd Tanous     }
1659f5ffd806SEd Tanous 
166010cb44f3SEd Tanous     handleLDAPPatch(std::move(activeDirectoryObject), asyncResp,
166110cb44f3SEd Tanous                     "ActiveDirectory");
166210cb44f3SEd Tanous     handleLDAPPatch(std::move(ldapObject), asyncResp, "LDAP");
1663f5ffd806SEd Tanous 
1664c1019828SEd Tanous     handleAuthMethodsPatch(asyncResp, auth);
1665f5ffd806SEd Tanous 
1666f5ffd806SEd Tanous     if (unlockTimeout)
1667f5ffd806SEd Tanous     {
1668d02aad39SEd Tanous         setDbusProperty(
1669e93abac6SGinu George             asyncResp, "AccountLockoutDuration",
1670e93abac6SGinu George             "xyz.openbmc_project.User.Manager",
1671d02aad39SEd Tanous             sdbusplus::message::object_path("/xyz/openbmc_project/user"),
16729ae226faSGeorge Liu             "xyz.openbmc_project.User.AccountPolicy", "AccountUnlockTimeout",
1673e93abac6SGinu George             *unlockTimeout);
1674f5ffd806SEd Tanous     }
1675f5ffd806SEd Tanous     if (lockoutThreshold)
1676f5ffd806SEd Tanous     {
1677d02aad39SEd Tanous         setDbusProperty(
1678e93abac6SGinu George             asyncResp, "AccountLockoutThreshold",
1679e93abac6SGinu George             "xyz.openbmc_project.User.Manager",
1680d02aad39SEd Tanous             sdbusplus::message::object_path("/xyz/openbmc_project/user"),
16819ae226faSGeorge Liu             "xyz.openbmc_project.User.AccountPolicy",
1682e93abac6SGinu George             "MaxLoginAttemptBeforeLockout", *lockoutThreshold);
1683f5ffd806SEd Tanous     }
16841ef4c342SEd Tanous }
1685f5ffd806SEd Tanous 
16864c7d4d33SEd Tanous inline void handleAccountCollectionHead(
16871ef4c342SEd Tanous     App& app, const crow::Request& req,
16881ef4c342SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
16891ef4c342SEd Tanous {
16903ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
169145ca1b86SEd Tanous     {
169245ca1b86SEd Tanous         return;
169345ca1b86SEd Tanous     }
16944c7d4d33SEd Tanous     asyncResp->res.addHeader(
16954c7d4d33SEd Tanous         boost::beast::http::field::link,
16964c7d4d33SEd Tanous         "</redfish/v1/JsonSchemas/ManagerAccountCollection.json>; rel=describedby");
16974c7d4d33SEd Tanous }
16984c7d4d33SEd Tanous 
16994c7d4d33SEd Tanous inline void handleAccountCollectionGet(
17004c7d4d33SEd Tanous     App& app, const crow::Request& req,
17014c7d4d33SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
17024c7d4d33SEd Tanous {
1703afd369c6SJiaqing Zhao     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1704afd369c6SJiaqing Zhao     {
1705afd369c6SJiaqing Zhao         return;
1706afd369c6SJiaqing Zhao     }
17073e72c202SNinad Palsule 
17083e72c202SNinad Palsule     if (req.session == nullptr)
17093e72c202SNinad Palsule     {
17103e72c202SNinad Palsule         messages::internalError(asyncResp->res);
17113e72c202SNinad Palsule         return;
17123e72c202SNinad Palsule     }
17133e72c202SNinad Palsule 
1714afd369c6SJiaqing Zhao     asyncResp->res.addHeader(
1715afd369c6SJiaqing Zhao         boost::beast::http::field::link,
1716afd369c6SJiaqing Zhao         "</redfish/v1/JsonSchemas/ManagerAccountCollection.json>; rel=describedby");
17171476687dSEd Tanous 
17181476687dSEd Tanous     asyncResp->res.jsonValue["@odata.id"] =
17191476687dSEd Tanous         "/redfish/v1/AccountService/Accounts";
17201ef4c342SEd Tanous     asyncResp->res.jsonValue["@odata.type"] = "#ManagerAccountCollection."
17211476687dSEd Tanous                                               "ManagerAccountCollection";
17221476687dSEd Tanous     asyncResp->res.jsonValue["Name"] = "Accounts Collection";
17231476687dSEd Tanous     asyncResp->res.jsonValue["Description"] = "BMC User Accounts";
17240f74e643SEd Tanous 
17256c51eab1SEd Tanous     Privileges effectiveUserPrivileges =
17263e72c202SNinad Palsule         redfish::getUserPrivileges(*req.session);
17276c51eab1SEd Tanous 
1728f5e29f33SJunLin Chen     std::string thisUser;
1729f5e29f33SJunLin Chen     if (req.session)
1730f5e29f33SJunLin Chen     {
1731f5e29f33SJunLin Chen         thisUser = req.session->username;
1732f5e29f33SJunLin Chen     }
17335eb468daSGeorge Liu     sdbusplus::message::object_path path("/xyz/openbmc_project/user");
17345eb468daSGeorge Liu     dbus::utility::getManagedObjects(
17355eb468daSGeorge Liu         "xyz.openbmc_project.User.Manager", path,
1736cef1ddfbSEd Tanous         [asyncResp, thisUser, effectiveUserPrivileges](
17375e7e2dc5SEd Tanous             const boost::system::error_code& ec,
1738711ac7a9SEd Tanous             const dbus::utility::ManagedObjectType& users) {
1739b9b2e0b2SEd Tanous             if (ec)
1740b9b2e0b2SEd Tanous             {
1741f12894f8SJason M. Bills                 messages::internalError(asyncResp->res);
1742b9b2e0b2SEd Tanous                 return;
1743b9b2e0b2SEd Tanous             }
1744b9b2e0b2SEd Tanous 
1745cef1ddfbSEd Tanous             bool userCanSeeAllAccounts =
1746002d39b4SEd Tanous                 effectiveUserPrivileges.isSupersetOf({"ConfigureUsers"});
1747cef1ddfbSEd Tanous 
1748cef1ddfbSEd Tanous             bool userCanSeeSelf =
1749002d39b4SEd Tanous                 effectiveUserPrivileges.isSupersetOf({"ConfigureSelf"});
1750cef1ddfbSEd Tanous 
1751002d39b4SEd Tanous             nlohmann::json& memberArray = asyncResp->res.jsonValue["Members"];
1752b9b2e0b2SEd Tanous             memberArray = nlohmann::json::array();
1753b9b2e0b2SEd Tanous 
17549eb808c1SEd Tanous             for (const auto& userpath : users)
1755b9b2e0b2SEd Tanous             {
17562dfd18efSEd Tanous                 std::string user = userpath.first.filename();
17572dfd18efSEd Tanous                 if (user.empty())
1758b9b2e0b2SEd Tanous                 {
17592dfd18efSEd Tanous                     messages::internalError(asyncResp->res);
176062598e31SEd Tanous                     BMCWEB_LOG_ERROR("Invalid firmware ID");
17612dfd18efSEd Tanous 
17622dfd18efSEd Tanous                     return;
1763b9b2e0b2SEd Tanous                 }
1764f365910cSGunnar Mills 
1765f365910cSGunnar Mills                 // As clarified by Redfish here:
1766f365910cSGunnar Mills                 // https://redfishforum.com/thread/281/manageraccountcollection-change-allows-account-enumeration
17676c51eab1SEd Tanous                 // Users without ConfigureUsers, only see their own
17686c51eab1SEd Tanous                 // account. Users with ConfigureUsers, see all
17696c51eab1SEd Tanous                 // accounts.
1770bd79bce8SPatrick Williams                 if (userCanSeeAllAccounts ||
1771bd79bce8SPatrick Williams                     (thisUser == user && userCanSeeSelf))
1772f365910cSGunnar Mills                 {
17731476687dSEd Tanous                     nlohmann::json::object_t member;
17743b32780dSEd Tanous                     member["@odata.id"] = boost::urls::format(
17753b32780dSEd Tanous                         "/redfish/v1/AccountService/Accounts/{}", user);
1776b2ba3072SPatrick Williams                     memberArray.emplace_back(std::move(member));
1777b9b2e0b2SEd Tanous                 }
1778f365910cSGunnar Mills             }
1779bd79bce8SPatrick Williams             asyncResp->res.jsonValue["Members@odata.count"] =
1780bd79bce8SPatrick Williams                 memberArray.size();
17815eb468daSGeorge Liu         });
17821ef4c342SEd Tanous }
17836c51eab1SEd Tanous 
178497e90da3SNinad Palsule inline void processAfterCreateUser(
178597e90da3SNinad Palsule     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
178697e90da3SNinad Palsule     const std::string& username, const std::string& password,
178797e90da3SNinad Palsule     const boost::system::error_code& ec, sdbusplus::message_t& m)
178897e90da3SNinad Palsule {
178997e90da3SNinad Palsule     if (ec)
179097e90da3SNinad Palsule     {
179197e90da3SNinad Palsule         userErrorMessageHandler(m.get_error(), asyncResp, username, "");
179297e90da3SNinad Palsule         return;
179397e90da3SNinad Palsule     }
179497e90da3SNinad Palsule 
179597e90da3SNinad Palsule     if (pamUpdatePassword(username, password) != PAM_SUCCESS)
179697e90da3SNinad Palsule     {
179797e90da3SNinad Palsule         // At this point we have a user that's been
179897e90da3SNinad Palsule         // created, but the password set
179997e90da3SNinad Palsule         // failed.Something is wrong, so delete the user
180097e90da3SNinad Palsule         // that we've already created
180197e90da3SNinad Palsule         sdbusplus::message::object_path tempObjPath(rootUserDbusPath);
180297e90da3SNinad Palsule         tempObjPath /= username;
180397e90da3SNinad Palsule         const std::string userPath(tempObjPath);
180497e90da3SNinad Palsule 
180597e90da3SNinad Palsule         crow::connections::systemBus->async_method_call(
180697e90da3SNinad Palsule             [asyncResp, password](const boost::system::error_code& ec3) {
180797e90da3SNinad Palsule                 if (ec3)
180897e90da3SNinad Palsule                 {
180997e90da3SNinad Palsule                     messages::internalError(asyncResp->res);
181097e90da3SNinad Palsule                     return;
181197e90da3SNinad Palsule                 }
181297e90da3SNinad Palsule 
181397e90da3SNinad Palsule                 // If password is invalid
18149bd80831SJason M. Bills                 messages::propertyValueFormatError(asyncResp->res, nullptr,
181597e90da3SNinad Palsule                                                    "Password");
181697e90da3SNinad Palsule             },
181797e90da3SNinad Palsule             "xyz.openbmc_project.User.Manager", userPath,
181897e90da3SNinad Palsule             "xyz.openbmc_project.Object.Delete", "Delete");
181997e90da3SNinad Palsule 
182062598e31SEd Tanous         BMCWEB_LOG_ERROR("pamUpdatePassword Failed");
182197e90da3SNinad Palsule         return;
182297e90da3SNinad Palsule     }
182397e90da3SNinad Palsule 
182497e90da3SNinad Palsule     messages::created(asyncResp->res);
182597e90da3SNinad Palsule     asyncResp->res.addHeader("Location",
182697e90da3SNinad Palsule                              "/redfish/v1/AccountService/Accounts/" + username);
182797e90da3SNinad Palsule }
182897e90da3SNinad Palsule 
182997e90da3SNinad Palsule inline void processAfterGetAllGroups(
183097e90da3SNinad Palsule     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
183197e90da3SNinad Palsule     const std::string& username, const std::string& password,
1832e01d0c36SEd Tanous     const std::string& roleId, bool enabled,
18339ba73934SNinad Palsule     std::optional<std::vector<std::string>> accountTypes,
183497e90da3SNinad Palsule     const std::vector<std::string>& allGroupsList)
183597e90da3SNinad Palsule {
18363e72c202SNinad Palsule     std::vector<std::string> userGroups;
18379ba73934SNinad Palsule     std::vector<std::string> accountTypeUserGroups;
18389ba73934SNinad Palsule 
18399ba73934SNinad Palsule     // If user specified account types then convert them to unix user groups
18409ba73934SNinad Palsule     if (accountTypes)
18419ba73934SNinad Palsule     {
18429ba73934SNinad Palsule         if (!getUserGroupFromAccountType(asyncResp->res, *accountTypes,
18439ba73934SNinad Palsule                                          accountTypeUserGroups))
18449ba73934SNinad Palsule         {
18459ba73934SNinad Palsule             // Problem in mapping Account Types to User Groups, Error already
18469ba73934SNinad Palsule             // logged.
18479ba73934SNinad Palsule             return;
18489ba73934SNinad Palsule         }
18499ba73934SNinad Palsule     }
18509ba73934SNinad Palsule 
18513e72c202SNinad Palsule     for (const auto& grp : allGroupsList)
18523e72c202SNinad Palsule     {
18539ba73934SNinad Palsule         // If user specified the account type then only accept groups which are
18549ba73934SNinad Palsule         // in the account types group list.
18559ba73934SNinad Palsule         if (!accountTypeUserGroups.empty())
18569ba73934SNinad Palsule         {
18579ba73934SNinad Palsule             bool found = false;
18589ba73934SNinad Palsule             for (const auto& grp1 : accountTypeUserGroups)
18599ba73934SNinad Palsule             {
18609ba73934SNinad Palsule                 if (grp == grp1)
18619ba73934SNinad Palsule                 {
18629ba73934SNinad Palsule                     found = true;
18639ba73934SNinad Palsule                     break;
18649ba73934SNinad Palsule                 }
18659ba73934SNinad Palsule             }
18669ba73934SNinad Palsule             if (!found)
18679ba73934SNinad Palsule             {
18689ba73934SNinad Palsule                 continue;
18699ba73934SNinad Palsule             }
18709ba73934SNinad Palsule         }
18719ba73934SNinad Palsule 
18723e72c202SNinad Palsule         // Console access is provided to the user who is a member of
18733e72c202SNinad Palsule         // hostconsole group and has a administrator role. So, set
18743e72c202SNinad Palsule         // hostconsole group only for the administrator.
18759ba73934SNinad Palsule         if ((grp == "hostconsole") && (roleId != "priv-admin"))
18763e72c202SNinad Palsule         {
18779ba73934SNinad Palsule             if (!accountTypeUserGroups.empty())
18789ba73934SNinad Palsule             {
187962598e31SEd Tanous                 BMCWEB_LOG_ERROR(
188062598e31SEd Tanous                     "Only administrator can get HostConsole access");
18819ba73934SNinad Palsule                 asyncResp->res.result(boost::beast::http::status::bad_request);
18829ba73934SNinad Palsule                 return;
18839ba73934SNinad Palsule             }
18849ba73934SNinad Palsule             continue;
18859ba73934SNinad Palsule         }
18863e72c202SNinad Palsule         userGroups.emplace_back(grp);
18873e72c202SNinad Palsule     }
18889ba73934SNinad Palsule 
18899ba73934SNinad Palsule     // Make sure user specified groups are valid. This is internal error because
18909ba73934SNinad Palsule     // it some inconsistencies between user manager and bmcweb.
18919ba73934SNinad Palsule     if (!accountTypeUserGroups.empty() &&
18929ba73934SNinad Palsule         accountTypeUserGroups.size() != userGroups.size())
18939ba73934SNinad Palsule     {
18949ba73934SNinad Palsule         messages::internalError(asyncResp->res);
18959ba73934SNinad Palsule         return;
18963e72c202SNinad Palsule     }
189797e90da3SNinad Palsule     crow::connections::systemBus->async_method_call(
189897e90da3SNinad Palsule         [asyncResp, username, password](const boost::system::error_code& ec2,
189997e90da3SNinad Palsule                                         sdbusplus::message_t& m) {
190097e90da3SNinad Palsule             processAfterCreateUser(asyncResp, username, password, ec2, m);
190197e90da3SNinad Palsule         },
190297e90da3SNinad Palsule         "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
19033e72c202SNinad Palsule         "xyz.openbmc_project.User.Manager", "CreateUser", username, userGroups,
1904e01d0c36SEd Tanous         roleId, enabled);
190597e90da3SNinad Palsule }
190697e90da3SNinad Palsule 
19071ef4c342SEd Tanous inline void handleAccountCollectionPost(
19081ef4c342SEd Tanous     App& app, const crow::Request& req,
19091ef4c342SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
19101ef4c342SEd Tanous {
19113ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
191245ca1b86SEd Tanous     {
191345ca1b86SEd Tanous         return;
191445ca1b86SEd Tanous     }
19159712f8acSEd Tanous     std::string username;
19169712f8acSEd Tanous     std::string password;
1917e01d0c36SEd Tanous     std::optional<std::string> roleIdJson;
1918e01d0c36SEd Tanous     std::optional<bool> enabledJson;
19199ba73934SNinad Palsule     std::optional<std::vector<std::string>> accountTypes;
1920afc474aeSMyung Bae     if (!json_util::readJsonPatch( //
1921afc474aeSMyung Bae             req, asyncResp->res, //
1922afc474aeSMyung Bae             "AccountTypes", accountTypes, //
1923afc474aeSMyung Bae             "Enabled", enabledJson, //
1924afc474aeSMyung Bae             "Password", password, //
1925afc474aeSMyung Bae             "RoleId", roleIdJson, //
1926afc474aeSMyung Bae             "UserName", username //
1927afc474aeSMyung Bae             ))
192804ae99ecSEd Tanous     {
192904ae99ecSEd Tanous         return;
193004ae99ecSEd Tanous     }
193104ae99ecSEd Tanous 
1932e01d0c36SEd Tanous     std::string roleId = roleIdJson.value_or("User");
1933e01d0c36SEd Tanous     std::string priv = getPrivilegeFromRoleId(roleId);
193484e12cb7SAppaRao Puli     if (priv.empty())
193504ae99ecSEd Tanous     {
1936e01d0c36SEd Tanous         messages::propertyValueNotInList(asyncResp->res, roleId, "RoleId");
193704ae99ecSEd Tanous         return;
193804ae99ecSEd Tanous     }
19399712f8acSEd Tanous     roleId = priv;
194004ae99ecSEd Tanous 
1941e01d0c36SEd Tanous     bool enabled = enabledJson.value_or(true);
1942e01d0c36SEd Tanous 
1943599c71d8SAyushi Smriti     // Reading AllGroups property
1944deae6a78SEd Tanous     dbus::utility::getProperty<std::vector<std::string>>(
1945deae6a78SEd Tanous         "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
1946deae6a78SEd Tanous         "xyz.openbmc_project.User.Manager", "AllGroups",
19479ba73934SNinad Palsule         [asyncResp, username, password{std::move(password)}, roleId, enabled,
19489ba73934SNinad Palsule          accountTypes](const boost::system::error_code& ec,
19491e1e598dSJonathan Doman                        const std::vector<std::string>& allGroupsList) {
1950599c71d8SAyushi Smriti             if (ec)
1951599c71d8SAyushi Smriti             {
1952a0735a4eSGunnar Mills                 BMCWEB_LOG_ERROR("D-Bus response error {}", ec);
1953599c71d8SAyushi Smriti                 messages::internalError(asyncResp->res);
1954599c71d8SAyushi Smriti                 return;
1955599c71d8SAyushi Smriti             }
1956599c71d8SAyushi Smriti 
19571e1e598dSJonathan Doman             if (allGroupsList.empty())
1958599c71d8SAyushi Smriti             {
1959599c71d8SAyushi Smriti                 messages::internalError(asyncResp->res);
1960599c71d8SAyushi Smriti                 return;
1961599c71d8SAyushi Smriti             }
1962599c71d8SAyushi Smriti 
1963bd79bce8SPatrick Williams             processAfterGetAllGroups(asyncResp, username, password, roleId,
1964bd79bce8SPatrick Williams                                      enabled, accountTypes, allGroupsList);
19651e1e598dSJonathan Doman         });
19661ef4c342SEd Tanous }
1967b9b2e0b2SEd Tanous 
19681ef4c342SEd Tanous inline void
19694c7d4d33SEd Tanous     handleAccountHead(App& app, const crow::Request& req,
19706c51eab1SEd Tanous                       const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
19714c7d4d33SEd Tanous                       const std::string& /*accountName*/)
19721ef4c342SEd Tanous {
19733ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
197445ca1b86SEd Tanous     {
197545ca1b86SEd Tanous         return;
197645ca1b86SEd Tanous     }
19774c7d4d33SEd Tanous     asyncResp->res.addHeader(
19784c7d4d33SEd Tanous         boost::beast::http::field::link,
19794c7d4d33SEd Tanous         "</redfish/v1/JsonSchemas/ManagerAccount/ManagerAccount.json>; rel=describedby");
19804c7d4d33SEd Tanous }
1981afd369c6SJiaqing Zhao 
19824c7d4d33SEd Tanous inline void
19834c7d4d33SEd Tanous     handleAccountGet(App& app, const crow::Request& req,
19844c7d4d33SEd Tanous                      const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
19854c7d4d33SEd Tanous                      const std::string& accountName)
19864c7d4d33SEd Tanous {
1987afd369c6SJiaqing Zhao     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1988afd369c6SJiaqing Zhao     {
1989afd369c6SJiaqing Zhao         return;
1990afd369c6SJiaqing Zhao     }
1991afd369c6SJiaqing Zhao     asyncResp->res.addHeader(
1992afd369c6SJiaqing Zhao         boost::beast::http::field::link,
1993afd369c6SJiaqing Zhao         "</redfish/v1/JsonSchemas/ManagerAccount/ManagerAccount.json>; rel=describedby");
1994afd369c6SJiaqing Zhao 
199525b54dbaSEd Tanous     if constexpr (BMCWEB_INSECURE_DISABLE_AUTH)
199625b54dbaSEd Tanous     {
1997031514fbSJunLin Chen         // If authentication is disabled, there are no user accounts
199825b54dbaSEd Tanous         messages::resourceNotFound(asyncResp->res, "ManagerAccount",
199925b54dbaSEd Tanous                                    accountName);
2000031514fbSJunLin Chen         return;
200125b54dbaSEd Tanous     }
2002afd369c6SJiaqing Zhao 
2003031514fbSJunLin Chen     if (req.session == nullptr)
2004031514fbSJunLin Chen     {
2005031514fbSJunLin Chen         messages::internalError(asyncResp->res);
2006031514fbSJunLin Chen         return;
2007031514fbSJunLin Chen     }
20086c51eab1SEd Tanous     if (req.session->username != accountName)
2009b9b2e0b2SEd Tanous     {
20106c51eab1SEd Tanous         // At this point we've determined that the user is trying to
20111ef4c342SEd Tanous         // modify a user that isn't them.  We need to verify that they
20121ef4c342SEd Tanous         // have permissions to modify other users, so re-run the auth
20131ef4c342SEd Tanous         // check with the same permissions, minus ConfigureSelf.
20146c51eab1SEd Tanous         Privileges effectiveUserPrivileges =
20153e72c202SNinad Palsule             redfish::getUserPrivileges(*req.session);
20161ef4c342SEd Tanous         Privileges requiredPermissionsToChangeNonSelf = {"ConfigureUsers",
20171ef4c342SEd Tanous                                                          "ConfigureManager"};
20186c51eab1SEd Tanous         if (!effectiveUserPrivileges.isSupersetOf(
20196c51eab1SEd Tanous                 requiredPermissionsToChangeNonSelf))
2020900f9497SJoseph Reynolds         {
202162598e31SEd Tanous             BMCWEB_LOG_DEBUG("GET Account denied access");
2022900f9497SJoseph Reynolds             messages::insufficientPrivilege(asyncResp->res);
2023900f9497SJoseph Reynolds             return;
2024900f9497SJoseph Reynolds         }
2025900f9497SJoseph Reynolds     }
2026900f9497SJoseph Reynolds 
20275eb468daSGeorge Liu     sdbusplus::message::object_path path("/xyz/openbmc_project/user");
20285eb468daSGeorge Liu     dbus::utility::getManagedObjects(
20295eb468daSGeorge Liu         "xyz.openbmc_project.User.Manager", path,
20301ef4c342SEd Tanous         [asyncResp,
20315e7e2dc5SEd Tanous          accountName](const boost::system::error_code& ec,
2032711ac7a9SEd Tanous                       const dbus::utility::ManagedObjectType& users) {
2033b9b2e0b2SEd Tanous             if (ec)
2034b9b2e0b2SEd Tanous             {
2035f12894f8SJason M. Bills                 messages::internalError(asyncResp->res);
2036b9b2e0b2SEd Tanous                 return;
2037b9b2e0b2SEd Tanous             }
20383544d2a7SEd Tanous             const auto userIt = std::ranges::find_if(
203980f79a40SMichael Shen                 users,
204080f79a40SMichael Shen                 [accountName](
2041b477fd44SP Dheeraj Srujan Kumar                     const std::pair<sdbusplus::message::object_path,
204280f79a40SMichael Shen                                     dbus::utility::DBusInterfacesMap>& user) {
204355f79e6fSEd Tanous                     return accountName == user.first.filename();
2044b477fd44SP Dheeraj Srujan Kumar                 });
2045b9b2e0b2SEd Tanous 
204684e12cb7SAppaRao Puli             if (userIt == users.end())
2047b9b2e0b2SEd Tanous             {
2048002d39b4SEd Tanous                 messages::resourceNotFound(asyncResp->res, "ManagerAccount",
2049002d39b4SEd Tanous                                            accountName);
205084e12cb7SAppaRao Puli                 return;
205184e12cb7SAppaRao Puli             }
20524e68c45bSAyushi Smriti 
20531476687dSEd Tanous             asyncResp->res.jsonValue["@odata.type"] =
205458345856SAbhishek Patel                 "#ManagerAccount.v1_7_0.ManagerAccount";
20551476687dSEd Tanous             asyncResp->res.jsonValue["Name"] = "User Account";
20561476687dSEd Tanous             asyncResp->res.jsonValue["Description"] = "User Account";
20571476687dSEd Tanous             asyncResp->res.jsonValue["Password"] = nullptr;
205858345856SAbhishek Patel             asyncResp->res.jsonValue["StrictAccountTypes"] = true;
20594e68c45bSAyushi Smriti 
206084e12cb7SAppaRao Puli             for (const auto& interface : userIt->second)
206165b0dc32SEd Tanous             {
2062002d39b4SEd Tanous                 if (interface.first == "xyz.openbmc_project.User.Attributes")
206365b0dc32SEd Tanous                 {
2064b437a535SAsmitha Karunanithi                     const bool* userEnabled = nullptr;
2065b437a535SAsmitha Karunanithi                     const bool* userLocked = nullptr;
2066b437a535SAsmitha Karunanithi                     const std::string* userPrivPtr = nullptr;
2067b437a535SAsmitha Karunanithi                     const bool* userPasswordExpired = nullptr;
2068b437a535SAsmitha Karunanithi                     const std::vector<std::string>* userGroups = nullptr;
2069b437a535SAsmitha Karunanithi 
2070b437a535SAsmitha Karunanithi                     const bool success = sdbusplus::unpackPropertiesNoThrow(
2071b437a535SAsmitha Karunanithi                         dbus_utils::UnpackErrorPrinter(), interface.second,
2072b437a535SAsmitha Karunanithi                         "UserEnabled", userEnabled,
2073b437a535SAsmitha Karunanithi                         "UserLockedForFailedAttempt", userLocked,
2074b437a535SAsmitha Karunanithi                         "UserPrivilege", userPrivPtr, "UserPasswordExpired",
2075b437a535SAsmitha Karunanithi                         userPasswordExpired, "UserGroups", userGroups);
2076b437a535SAsmitha Karunanithi                     if (!success)
207765b0dc32SEd Tanous                     {
2078b437a535SAsmitha Karunanithi                         messages::internalError(asyncResp->res);
2079b437a535SAsmitha Karunanithi                         return;
2080b437a535SAsmitha Karunanithi                     }
208165b0dc32SEd Tanous                     if (userEnabled == nullptr)
208265b0dc32SEd Tanous                     {
208362598e31SEd Tanous                         BMCWEB_LOG_ERROR("UserEnabled wasn't a bool");
208484e12cb7SAppaRao Puli                         messages::internalError(asyncResp->res);
208584e12cb7SAppaRao Puli                         return;
208665b0dc32SEd Tanous                     }
2087002d39b4SEd Tanous                     asyncResp->res.jsonValue["Enabled"] = *userEnabled;
2088b437a535SAsmitha Karunanithi 
208965b0dc32SEd Tanous                     if (userLocked == nullptr)
209065b0dc32SEd Tanous                     {
209162598e31SEd Tanous                         BMCWEB_LOG_ERROR("UserLockedForF"
209284e12cb7SAppaRao Puli                                          "ailedAttempt "
209362598e31SEd Tanous                                          "wasn't a bool");
209484e12cb7SAppaRao Puli                         messages::internalError(asyncResp->res);
209584e12cb7SAppaRao Puli                         return;
209665b0dc32SEd Tanous                     }
2097002d39b4SEd Tanous                     asyncResp->res.jsonValue["Locked"] = *userLocked;
209820fa6a2cSEd Tanous                     nlohmann::json::array_t allowed;
209920fa6a2cSEd Tanous                     // can only unlock accounts
210020fa6a2cSEd Tanous                     allowed.emplace_back("false");
2101b437a535SAsmitha Karunanithi                     asyncResp->res.jsonValue["Locked@Redfish.AllowableValues"] =
210220fa6a2cSEd Tanous                         std::move(allowed);
2103b437a535SAsmitha Karunanithi 
210454fc587aSNagaraju Goruganti                     if (userPrivPtr == nullptr)
210584e12cb7SAppaRao Puli                     {
210662598e31SEd Tanous                         BMCWEB_LOG_ERROR("UserPrivilege wasn't a "
210762598e31SEd Tanous                                          "string");
210884e12cb7SAppaRao Puli                         messages::internalError(asyncResp->res);
210984e12cb7SAppaRao Puli                         return;
211084e12cb7SAppaRao Puli                     }
2111b437a535SAsmitha Karunanithi                     std::string role = getRoleIdFromPrivilege(*userPrivPtr);
211254fc587aSNagaraju Goruganti                     if (role.empty())
211384e12cb7SAppaRao Puli                     {
211462598e31SEd Tanous                         BMCWEB_LOG_ERROR("Invalid user role");
211584e12cb7SAppaRao Puli                         messages::internalError(asyncResp->res);
211684e12cb7SAppaRao Puli                         return;
211784e12cb7SAppaRao Puli                     }
211854fc587aSNagaraju Goruganti                     asyncResp->res.jsonValue["RoleId"] = role;
211984e12cb7SAppaRao Puli 
21201476687dSEd Tanous                     nlohmann::json& roleEntry =
2121002d39b4SEd Tanous                         asyncResp->res.jsonValue["Links"]["Role"];
21223b32780dSEd Tanous                     roleEntry["@odata.id"] = boost::urls::format(
21233b32780dSEd Tanous                         "/redfish/v1/AccountService/Roles/{}", role);
2124b437a535SAsmitha Karunanithi 
21253bf4e632SJoseph Reynolds                     if (userPasswordExpired == nullptr)
21263bf4e632SJoseph Reynolds                     {
2127b437a535SAsmitha Karunanithi                         BMCWEB_LOG_ERROR("UserPasswordExpired wasn't a bool");
21283bf4e632SJoseph Reynolds                         messages::internalError(asyncResp->res);
21293bf4e632SJoseph Reynolds                         return;
21303bf4e632SJoseph Reynolds                     }
2131002d39b4SEd Tanous                     asyncResp->res.jsonValue["PasswordChangeRequired"] =
21323bf4e632SJoseph Reynolds                         *userPasswordExpired;
2133b437a535SAsmitha Karunanithi 
2134c7229815SAbhishek Patel                     if (userGroups == nullptr)
2135c7229815SAbhishek Patel                     {
2136b437a535SAsmitha Karunanithi                         BMCWEB_LOG_ERROR("userGroups wasn't a string vector");
2137c7229815SAbhishek Patel                         messages::internalError(asyncResp->res);
2138c7229815SAbhishek Patel                         return;
2139c7229815SAbhishek Patel                     }
2140b437a535SAsmitha Karunanithi                     if (!translateUserGroup(*userGroups, asyncResp->res))
2141c7229815SAbhishek Patel                     {
214262598e31SEd Tanous                         BMCWEB_LOG_ERROR("userGroups mapping failed");
2143c7229815SAbhishek Patel                         messages::internalError(asyncResp->res);
2144c7229815SAbhishek Patel                         return;
2145c7229815SAbhishek Patel                     }
2146c7229815SAbhishek Patel                 }
214765b0dc32SEd Tanous             }
214865b0dc32SEd Tanous 
21493b32780dSEd Tanous             asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
21503b32780dSEd Tanous                 "/redfish/v1/AccountService/Accounts/{}", accountName);
2151b9b2e0b2SEd Tanous             asyncResp->res.jsonValue["Id"] = accountName;
2152b9b2e0b2SEd Tanous             asyncResp->res.jsonValue["UserName"] = accountName;
21535eb468daSGeorge Liu         });
21541ef4c342SEd Tanous }
2155a840879dSEd Tanous 
21561ef4c342SEd Tanous inline void
215720fc307fSGunnar Mills     handleAccountDelete(App& app, const crow::Request& req,
21586c51eab1SEd Tanous                         const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
21591ef4c342SEd Tanous                         const std::string& username)
21601ef4c342SEd Tanous {
21613ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
216245ca1b86SEd Tanous     {
216345ca1b86SEd Tanous         return;
216445ca1b86SEd Tanous     }
21651ef4c342SEd Tanous 
216625b54dbaSEd Tanous     if constexpr (BMCWEB_INSECURE_DISABLE_AUTH)
216725b54dbaSEd Tanous     {
2168031514fbSJunLin Chen         // If authentication is disabled, there are no user accounts
2169d8a5d5d8SJiaqing Zhao         messages::resourceNotFound(asyncResp->res, "ManagerAccount", username);
2170031514fbSJunLin Chen         return;
217125b54dbaSEd Tanous     }
21721ef4c342SEd Tanous     sdbusplus::message::object_path tempObjPath(rootUserDbusPath);
21731ef4c342SEd Tanous     tempObjPath /= username;
21741ef4c342SEd Tanous     const std::string userPath(tempObjPath);
21751ef4c342SEd Tanous 
21761ef4c342SEd Tanous     crow::connections::systemBus->async_method_call(
21775e7e2dc5SEd Tanous         [asyncResp, username](const boost::system::error_code& ec) {
21781ef4c342SEd Tanous             if (ec)
21791ef4c342SEd Tanous             {
2180d8a5d5d8SJiaqing Zhao                 messages::resourceNotFound(asyncResp->res, "ManagerAccount",
21811ef4c342SEd Tanous                                            username);
21821ef4c342SEd Tanous                 return;
21831ef4c342SEd Tanous             }
21841ef4c342SEd Tanous 
21851ef4c342SEd Tanous             messages::accountRemoved(asyncResp->res);
21861ef4c342SEd Tanous         },
21871ef4c342SEd Tanous         "xyz.openbmc_project.User.Manager", userPath,
21881ef4c342SEd Tanous         "xyz.openbmc_project.Object.Delete", "Delete");
21891ef4c342SEd Tanous }
21901ef4c342SEd Tanous 
21911ef4c342SEd Tanous inline void
21921ef4c342SEd Tanous     handleAccountPatch(App& app, const crow::Request& req,
21931ef4c342SEd Tanous                        const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
21941ef4c342SEd Tanous                        const std::string& username)
21951ef4c342SEd Tanous {
21961ef4c342SEd Tanous     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
21971ef4c342SEd Tanous     {
21981ef4c342SEd Tanous         return;
21991ef4c342SEd Tanous     }
220025b54dbaSEd Tanous     if constexpr (BMCWEB_INSECURE_DISABLE_AUTH)
220125b54dbaSEd Tanous     {
22021ef4c342SEd Tanous         // If authentication is disabled, there are no user accounts
2203d8a5d5d8SJiaqing Zhao         messages::resourceNotFound(asyncResp->res, "ManagerAccount", username);
22041ef4c342SEd Tanous         return;
220525b54dbaSEd Tanous     }
2206a24526dcSEd Tanous     std::optional<std::string> newUserName;
2207a24526dcSEd Tanous     std::optional<std::string> password;
2208a24526dcSEd Tanous     std::optional<bool> enabled;
2209a24526dcSEd Tanous     std::optional<std::string> roleId;
221024c8542dSRatan Gupta     std::optional<bool> locked;
221158345856SAbhishek Patel     std::optional<std::vector<std::string>> accountTypes;
221258345856SAbhishek Patel 
2213031514fbSJunLin Chen     if (req.session == nullptr)
2214031514fbSJunLin Chen     {
2215031514fbSJunLin Chen         messages::internalError(asyncResp->res);
2216031514fbSJunLin Chen         return;
2217031514fbSJunLin Chen     }
2218031514fbSJunLin Chen 
22192b9c1dfeSEd Tanous     bool userSelf = (username == req.session->username);
22202b9c1dfeSEd Tanous 
2221e9cc5172SEd Tanous     Privileges effectiveUserPrivileges =
22223e72c202SNinad Palsule         redfish::getUserPrivileges(*req.session);
2223e9cc5172SEd Tanous     Privileges configureUsers = {"ConfigureUsers"};
2224e9cc5172SEd Tanous     bool userHasConfigureUsers =
2225e9cc5172SEd Tanous         effectiveUserPrivileges.isSupersetOf(configureUsers);
2226e9cc5172SEd Tanous     if (userHasConfigureUsers)
2227e9cc5172SEd Tanous     {
2228e9cc5172SEd Tanous         // Users with ConfigureUsers can modify for all users
2229afc474aeSMyung Bae         if (!json_util::readJsonPatch( //
2230afc474aeSMyung Bae                 req, asyncResp->res, //
2231afc474aeSMyung Bae                 "AccountTypes", accountTypes, //
2232afc474aeSMyung Bae                 "Enabled", enabled, //
2233afc474aeSMyung Bae                 "Locked", locked, //
2234afc474aeSMyung Bae                 "Password", password, //
2235afc474aeSMyung Bae                 "RoleId", roleId, //
2236afc474aeSMyung Bae                 "UserName", newUserName //
2237afc474aeSMyung Bae                 ))
2238a840879dSEd Tanous         {
2239a840879dSEd Tanous             return;
2240a840879dSEd Tanous         }
2241e9cc5172SEd Tanous     }
2242e9cc5172SEd Tanous     else
2243900f9497SJoseph Reynolds     {
2244e9cc5172SEd Tanous         // ConfigureSelf accounts can only modify their own account
224558345856SAbhishek Patel         if (!userSelf)
2246900f9497SJoseph Reynolds         {
2247900f9497SJoseph Reynolds             messages::insufficientPrivilege(asyncResp->res);
2248900f9497SJoseph Reynolds             return;
2249900f9497SJoseph Reynolds         }
2250031514fbSJunLin Chen 
2251e9cc5172SEd Tanous         // ConfigureSelf accounts can only modify their password
22521ef4c342SEd Tanous         if (!json_util::readJsonPatch(req, asyncResp->res, "Password",
22531ef4c342SEd Tanous                                       password))
2254e9cc5172SEd Tanous         {
2255e9cc5172SEd Tanous             return;
2256e9cc5172SEd Tanous         }
2257900f9497SJoseph Reynolds     }
2258900f9497SJoseph Reynolds 
225966b5ca76Sjayaprakash Mutyala     // if user name is not provided in the patch method or if it
22606c51eab1SEd Tanous     // matches the user name in the URI, then we are treating it as
22616c51eab1SEd Tanous     // updating user properties other then username. If username
22626c51eab1SEd Tanous     // provided doesn't match the URI, then we are treating this as
22636c51eab1SEd Tanous     // user rename request.
226466b5ca76Sjayaprakash Mutyala     if (!newUserName || (newUserName.value() == username))
2265a840879dSEd Tanous     {
22661ef4c342SEd Tanous         updateUserProperties(asyncResp, username, password, enabled, roleId,
2267e518ef32SRavi Teja                              locked, accountTypes, userSelf, req.session);
226884e12cb7SAppaRao Puli         return;
226984e12cb7SAppaRao Puli     }
227084e12cb7SAppaRao Puli     crow::connections::systemBus->async_method_call(
22716c51eab1SEd Tanous         [asyncResp, username, password(std::move(password)),
22721ef4c342SEd Tanous          roleId(std::move(roleId)), enabled, newUser{std::string(*newUserName)},
2273e518ef32SRavi Teja          locked, userSelf, req, accountTypes(std::move(accountTypes))](
2274e81de512SEd Tanous             const boost::system::error_code& ec, sdbusplus::message_t& m) {
227584e12cb7SAppaRao Puli             if (ec)
227684e12cb7SAppaRao Puli             {
2277002d39b4SEd Tanous                 userErrorMessageHandler(m.get_error(), asyncResp, newUser,
2278002d39b4SEd Tanous                                         username);
2279a840879dSEd Tanous                 return;
2280a840879dSEd Tanous             }
2281a840879dSEd Tanous 
2282002d39b4SEd Tanous             updateUserProperties(asyncResp, newUser, password, enabled, roleId,
2283e518ef32SRavi Teja                                  locked, accountTypes, userSelf, req.session);
228484e12cb7SAppaRao Puli         },
22851ef4c342SEd Tanous         "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
228684e12cb7SAppaRao Puli         "xyz.openbmc_project.User.Manager", "RenameUser", username,
228784e12cb7SAppaRao Puli         *newUserName);
22881ef4c342SEd Tanous }
22891ef4c342SEd Tanous 
22901ef4c342SEd Tanous inline void requestAccountServiceRoutes(App& app)
22911ef4c342SEd Tanous {
22921ef4c342SEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/AccountService/")
22934c7d4d33SEd Tanous         .privileges(redfish::privileges::headAccountService)
22944c7d4d33SEd Tanous         .methods(boost::beast::http::verb::head)(
22954c7d4d33SEd Tanous             std::bind_front(handleAccountServiceHead, std::ref(app)));
22964c7d4d33SEd Tanous 
22974c7d4d33SEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/AccountService/")
22981ef4c342SEd Tanous         .privileges(redfish::privileges::getAccountService)
22991ef4c342SEd Tanous         .methods(boost::beast::http::verb::get)(
23001ef4c342SEd Tanous             std::bind_front(handleAccountServiceGet, std::ref(app)));
23011ef4c342SEd Tanous 
23021ef4c342SEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/AccountService/")
23031ef4c342SEd Tanous         .privileges(redfish::privileges::patchAccountService)
23041ef4c342SEd Tanous         .methods(boost::beast::http::verb::patch)(
23051ef4c342SEd Tanous             std::bind_front(handleAccountServicePatch, std::ref(app)));
23061ef4c342SEd Tanous 
23071aa375b8SEd Tanous     BMCWEB_ROUTE(
23081aa375b8SEd Tanous         app,
2309e9f12014SEd Tanous         "/redfish/v1/AccountService/MultiFactorAuth/ClientCertificate/Certificates/")
23101aa375b8SEd Tanous         .privileges(redfish::privileges::headCertificateCollection)
23111aa375b8SEd Tanous         .methods(boost::beast::http::verb::head)(std::bind_front(
23121aa375b8SEd Tanous             handleAccountServiceClientCertificatesHead, std::ref(app)));
23131aa375b8SEd Tanous 
23141aa375b8SEd Tanous     BMCWEB_ROUTE(
23151aa375b8SEd Tanous         app,
2316e9f12014SEd Tanous         "/redfish/v1/AccountService/MultiFactorAuth/ClientCertificate/Certificates/")
23171aa375b8SEd Tanous         .privileges(redfish::privileges::getCertificateCollection)
23181aa375b8SEd Tanous         .methods(boost::beast::http::verb::get)(std::bind_front(
23191aa375b8SEd Tanous             handleAccountServiceClientCertificatesGet, std::ref(app)));
23201aa375b8SEd Tanous 
23211aa375b8SEd Tanous     BMCWEB_ROUTE(
23221aa375b8SEd Tanous         app,
2323e9f12014SEd Tanous         "/redfish/v1/AccountService/MultiFactorAuth/ClientCertificate/Certificates/<str>/")
23241aa375b8SEd Tanous         .privileges(redfish::privileges::headCertificate)
23251aa375b8SEd Tanous         .methods(boost::beast::http::verb::head)(std::bind_front(
23261aa375b8SEd Tanous             handleAccountServiceClientCertificatesInstanceHead, std::ref(app)));
23271aa375b8SEd Tanous 
23281aa375b8SEd Tanous     BMCWEB_ROUTE(
23291aa375b8SEd Tanous         app,
23301aa375b8SEd Tanous         "/redfish/v1/AccountService/MultiFactorAuth/ClientCertificate/Certificates/<str>/")
23311aa375b8SEd Tanous         .privileges(redfish::privileges::getCertificate)
23321aa375b8SEd Tanous         .methods(boost::beast::http::verb::get)(std::bind_front(
23331aa375b8SEd Tanous             handleAccountServiceClientCertificatesInstanceGet, std::ref(app)));
23341aa375b8SEd Tanous 
23351ef4c342SEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/")
23364c7d4d33SEd Tanous         .privileges(redfish::privileges::headManagerAccountCollection)
23374c7d4d33SEd Tanous         .methods(boost::beast::http::verb::head)(
23384c7d4d33SEd Tanous             std::bind_front(handleAccountCollectionHead, std::ref(app)));
23394c7d4d33SEd Tanous 
23404c7d4d33SEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/")
23411ef4c342SEd Tanous         .privileges(redfish::privileges::getManagerAccountCollection)
23421ef4c342SEd Tanous         .methods(boost::beast::http::verb::get)(
23431ef4c342SEd Tanous             std::bind_front(handleAccountCollectionGet, std::ref(app)));
23441ef4c342SEd Tanous 
23451ef4c342SEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/")
23461ef4c342SEd Tanous         .privileges(redfish::privileges::postManagerAccountCollection)
23471ef4c342SEd Tanous         .methods(boost::beast::http::verb::post)(
23481ef4c342SEd Tanous             std::bind_front(handleAccountCollectionPost, std::ref(app)));
23491ef4c342SEd Tanous 
23501ef4c342SEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/<str>/")
23514c7d4d33SEd Tanous         .privileges(redfish::privileges::headManagerAccount)
23524c7d4d33SEd Tanous         .methods(boost::beast::http::verb::head)(
23534c7d4d33SEd Tanous             std::bind_front(handleAccountHead, std::ref(app)));
23544c7d4d33SEd Tanous 
23554c7d4d33SEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/<str>/")
23561ef4c342SEd Tanous         .privileges(redfish::privileges::getManagerAccount)
23571ef4c342SEd Tanous         .methods(boost::beast::http::verb::get)(
23581ef4c342SEd Tanous             std::bind_front(handleAccountGet, std::ref(app)));
23591ef4c342SEd Tanous 
23601ef4c342SEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/<str>/")
23611ef4c342SEd Tanous         // TODO this privilege should be using the generated endpoints, but
23621ef4c342SEd Tanous         // because of the special handling of ConfigureSelf, it's not able to
23631ef4c342SEd Tanous         // yet
23641ef4c342SEd Tanous         .privileges({{"ConfigureUsers"}, {"ConfigureSelf"}})
23651ef4c342SEd Tanous         .methods(boost::beast::http::verb::patch)(
23661ef4c342SEd Tanous             std::bind_front(handleAccountPatch, std::ref(app)));
236784e12cb7SAppaRao Puli 
23686c51eab1SEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/<str>/")
2369ed398213SEd Tanous         .privileges(redfish::privileges::deleteManagerAccount)
23706c51eab1SEd Tanous         .methods(boost::beast::http::verb::delete_)(
237120fc307fSGunnar Mills             std::bind_front(handleAccountDelete, std::ref(app)));
237206e086d9SEd Tanous }
237388d16c9aSLewanczyk, Dawid 
237488d16c9aSLewanczyk, Dawid } // namespace redfish
2375