xref: /openbmc/bmcweb/features/redfish/lib/account_service.hpp (revision afc474aef028555fc0a6deb425bdad86f0a34db6)
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 
420*afc474aeSMyung Bae             if (!json_util::readJsonObject( //
421*afc474aeSMyung Bae                     *obj, asyncResp->res, //
422*afc474aeSMyung Bae                     "LocalRole", localRole, //
423*afc474aeSMyung Bae                     "RemoteGroup", remoteGroup //
424*afc474aeSMyung 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 
109458345856SAbhishek Patel inline void updateUserProperties(
109558345856SAbhishek Patel     std::shared_ptr<bmcweb::AsyncResp> asyncResp, const std::string& username,
1096618c14b4SEd Tanous     const std::optional<std::string>& password,
1097618c14b4SEd Tanous     const std::optional<bool>& enabled,
109858345856SAbhishek Patel     const std::optional<std::string>& roleId, const std::optional<bool>& locked,
1099e518ef32SRavi Teja     std::optional<std::vector<std::string>> accountTypes, bool userSelf,
1100e518ef32SRavi Teja     const std::shared_ptr<persistent_data::UserSession>& session)
11011abe55efSEd Tanous {
1102b477fd44SP Dheeraj Srujan Kumar     sdbusplus::message::object_path tempObjPath(rootUserDbusPath);
1103b477fd44SP Dheeraj Srujan Kumar     tempObjPath /= username;
1104b477fd44SP Dheeraj Srujan Kumar     std::string dbusObjectPath(tempObjPath);
11056c51eab1SEd Tanous 
11066c51eab1SEd Tanous     dbus::utility::checkDbusPathExists(
1107e518ef32SRavi Teja         dbusObjectPath,
1108e518ef32SRavi Teja         [dbusObjectPath, username, password, roleId, enabled, locked,
1109e518ef32SRavi Teja          accountTypes(std::move(accountTypes)), userSelf, session,
1110e518ef32SRavi Teja          asyncResp{std::move(asyncResp)}](int rc) {
1111e662eae8SEd Tanous             if (rc <= 0)
11126c51eab1SEd Tanous             {
1113d8a5d5d8SJiaqing Zhao                 messages::resourceNotFound(asyncResp->res, "ManagerAccount",
11146c51eab1SEd Tanous                                            username);
11156c51eab1SEd Tanous                 return;
11166c51eab1SEd Tanous             }
11176c51eab1SEd Tanous 
11186c51eab1SEd Tanous             if (password)
11196c51eab1SEd Tanous             {
11206c51eab1SEd Tanous                 int retval = pamUpdatePassword(username, *password);
11216c51eab1SEd Tanous 
11226c51eab1SEd Tanous                 if (retval == PAM_USER_UNKNOWN)
11236c51eab1SEd Tanous                 {
1124d8a5d5d8SJiaqing Zhao                     messages::resourceNotFound(asyncResp->res, "ManagerAccount",
11256c51eab1SEd Tanous                                                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()
1144bd79bce8SPatrick Williams                         .removeSessionsByUsernameExceptSession(username,
1145bd79bce8SPatrick Williams                                                                session);
1146e7b1b62bSEd Tanous                     messages::success(asyncResp->res);
1147e7b1b62bSEd Tanous                 }
11486c51eab1SEd Tanous             }
11496c51eab1SEd Tanous 
11506c51eab1SEd Tanous             if (enabled)
11516c51eab1SEd Tanous             {
1152bd79bce8SPatrick Williams                 setDbusProperty(
1153bd79bce8SPatrick Williams                     asyncResp, "Enabled", "xyz.openbmc_project.User.Manager",
1154bd79bce8SPatrick Williams                     dbusObjectPath, "xyz.openbmc_project.User.Attributes",
1155e93abac6SGinu George                     "UserEnabled", *enabled);
11566c51eab1SEd Tanous             }
11576c51eab1SEd Tanous 
11586c51eab1SEd Tanous             if (roleId)
11596c51eab1SEd Tanous             {
11606c51eab1SEd Tanous                 std::string priv = getPrivilegeFromRoleId(*roleId);
11616c51eab1SEd Tanous                 if (priv.empty())
11626c51eab1SEd Tanous                 {
1163e2616cc5SEd Tanous                     messages::propertyValueNotInList(asyncResp->res, true,
1164e2616cc5SEd Tanous                                                      "Locked");
11656c51eab1SEd Tanous                     return;
11666c51eab1SEd Tanous                 }
1167bd79bce8SPatrick Williams                 setDbusProperty(
1168bd79bce8SPatrick Williams                     asyncResp, "RoleId", "xyz.openbmc_project.User.Manager",
1169bd79bce8SPatrick Williams                     dbusObjectPath, "xyz.openbmc_project.User.Attributes",
1170e93abac6SGinu George                     "UserPrivilege", priv);
11716c51eab1SEd Tanous             }
11726c51eab1SEd Tanous 
11736c51eab1SEd Tanous             if (locked)
11746c51eab1SEd Tanous             {
11756c51eab1SEd Tanous                 // admin can unlock the account which is locked by
11766c51eab1SEd Tanous                 // successive authentication failures but admin should
11776c51eab1SEd Tanous                 // not be allowed to lock an account.
11786c51eab1SEd Tanous                 if (*locked)
11796c51eab1SEd Tanous                 {
11806c51eab1SEd Tanous                     messages::propertyValueNotInList(asyncResp->res, "true",
11816c51eab1SEd Tanous                                                      "Locked");
11826c51eab1SEd Tanous                     return;
11836c51eab1SEd Tanous                 }
1184bd79bce8SPatrick Williams                 setDbusProperty(
1185bd79bce8SPatrick Williams                     asyncResp, "Locked", "xyz.openbmc_project.User.Manager",
1186bd79bce8SPatrick Williams                     dbusObjectPath, "xyz.openbmc_project.User.Attributes",
1187e93abac6SGinu George                     "UserLockedForFailedAttempt", *locked);
11886c51eab1SEd Tanous             }
118958345856SAbhishek Patel 
119058345856SAbhishek Patel             if (accountTypes)
119158345856SAbhishek Patel             {
119258345856SAbhishek Patel                 patchAccountTypes(*accountTypes, asyncResp, dbusObjectPath,
119358345856SAbhishek Patel                                   userSelf);
119458345856SAbhishek Patel             }
11956c51eab1SEd Tanous         });
11966c51eab1SEd Tanous }
11976c51eab1SEd Tanous 
11984c7d4d33SEd Tanous inline void handleAccountServiceHead(
11994c7d4d33SEd Tanous     App& app, const crow::Request& req,
12001ef4c342SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
12016c51eab1SEd Tanous {
12023ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
120345ca1b86SEd Tanous     {
120445ca1b86SEd Tanous         return;
120545ca1b86SEd Tanous     }
12064c7d4d33SEd Tanous     asyncResp->res.addHeader(
12074c7d4d33SEd Tanous         boost::beast::http::field::link,
12084c7d4d33SEd Tanous         "</redfish/v1/JsonSchemas/AccountService/AccountService.json>; rel=describedby");
12094c7d4d33SEd Tanous }
12104c7d4d33SEd Tanous 
12114c7d4d33SEd Tanous inline void
12121aa375b8SEd Tanous     getClientCertificates(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
12131aa375b8SEd Tanous                           const nlohmann::json::json_pointer& keyLocation)
12141aa375b8SEd Tanous {
12151aa375b8SEd Tanous     boost::urls::url url(
12161aa375b8SEd Tanous         "/redfish/v1/AccountService/MultiFactorAuth/ClientCertificate/Certificates");
12171aa375b8SEd Tanous     std::array<std::string_view, 1> interfaces = {
12181aa375b8SEd Tanous         "xyz.openbmc_project.Certs.Certificate"};
12191aa375b8SEd Tanous     std::string path = "/xyz/openbmc_project/certs/authority/truststore";
12201aa375b8SEd Tanous 
12211aa375b8SEd Tanous     collection_util::getCollectionToKey(asyncResp, url, interfaces, path,
12221aa375b8SEd Tanous                                         keyLocation);
12231aa375b8SEd Tanous }
12241aa375b8SEd Tanous 
12251aa375b8SEd Tanous inline void handleAccountServiceClientCertificatesInstanceHead(
12261aa375b8SEd Tanous     App& app, const crow::Request& req,
12271aa375b8SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
12281aa375b8SEd Tanous     const std::string& /*id*/)
12291aa375b8SEd Tanous {
12301aa375b8SEd Tanous     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
12311aa375b8SEd Tanous     {
12321aa375b8SEd Tanous         return;
12331aa375b8SEd Tanous     }
12341aa375b8SEd Tanous 
12351aa375b8SEd Tanous     asyncResp->res.addHeader(
12361aa375b8SEd Tanous         boost::beast::http::field::link,
12371aa375b8SEd Tanous         "</redfish/v1/JsonSchemas/Certificate/Certificate.json>; rel=describedby");
12381aa375b8SEd Tanous }
12391aa375b8SEd Tanous 
12401aa375b8SEd Tanous inline void handleAccountServiceClientCertificatesInstanceGet(
12411aa375b8SEd Tanous     App& app, const crow::Request& req,
12421aa375b8SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id)
12431aa375b8SEd Tanous {
12441aa375b8SEd Tanous     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
12451aa375b8SEd Tanous     {
12461aa375b8SEd Tanous         return;
12471aa375b8SEd Tanous     }
12481aa375b8SEd Tanous     BMCWEB_LOG_DEBUG("ClientCertificate Certificate ID={}", id);
12491aa375b8SEd Tanous     const boost::urls::url certURL = boost::urls::format(
12501aa375b8SEd Tanous         "/redfish/v1/AccountService/MultiFactorAuth/ClientCertificate/Certificates/{}",
12511aa375b8SEd Tanous         id);
12521aa375b8SEd Tanous     std::string objPath =
12531aa375b8SEd Tanous         sdbusplus::message::object_path(certs::authorityObjectPath) / id;
12541aa375b8SEd Tanous     getCertificateProperties(
12551aa375b8SEd Tanous         asyncResp, objPath,
12561aa375b8SEd Tanous         "xyz.openbmc_project.Certs.Manager.Authority.Truststore", id, certURL,
12571aa375b8SEd Tanous         "Client Certificate");
12581aa375b8SEd Tanous }
12591aa375b8SEd Tanous 
12601aa375b8SEd Tanous inline void handleAccountServiceClientCertificatesHead(
12611aa375b8SEd Tanous     App& app, const crow::Request& req,
12621aa375b8SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
12631aa375b8SEd Tanous {
12641aa375b8SEd Tanous     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
12651aa375b8SEd Tanous     {
12661aa375b8SEd Tanous         return;
12671aa375b8SEd Tanous     }
12681aa375b8SEd Tanous 
12691aa375b8SEd Tanous     asyncResp->res.addHeader(
12701aa375b8SEd Tanous         boost::beast::http::field::link,
12711aa375b8SEd Tanous         "</redfish/v1/JsonSchemas/CertificateCollection/CertificateCollection.json>; rel=describedby");
12721aa375b8SEd Tanous }
12731aa375b8SEd Tanous 
12741aa375b8SEd Tanous inline void handleAccountServiceClientCertificatesGet(
12751aa375b8SEd Tanous     App& app, const crow::Request& req,
12761aa375b8SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
12771aa375b8SEd Tanous {
12781aa375b8SEd Tanous     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
12791aa375b8SEd Tanous     {
12801aa375b8SEd Tanous         return;
12811aa375b8SEd Tanous     }
12821aa375b8SEd Tanous     getClientCertificates(asyncResp, "/Members"_json_pointer);
12831aa375b8SEd Tanous }
12841aa375b8SEd Tanous 
12853ce3688aSEd Tanous using account_service::CertificateMappingAttribute;
12863ce3688aSEd Tanous using persistent_data::MTLSCommonNameParseMode;
12873ce3688aSEd Tanous inline CertificateMappingAttribute
12883ce3688aSEd Tanous     getCertificateMapping(MTLSCommonNameParseMode parse)
12893ce3688aSEd Tanous {
12903ce3688aSEd Tanous     switch (parse)
12913ce3688aSEd Tanous     {
12923ce3688aSEd Tanous         case MTLSCommonNameParseMode::CommonName:
12933ce3688aSEd Tanous         {
12943ce3688aSEd Tanous             return CertificateMappingAttribute::CommonName;
12953ce3688aSEd Tanous         }
12963ce3688aSEd Tanous         break;
12973ce3688aSEd Tanous         case MTLSCommonNameParseMode::Whole:
12983ce3688aSEd Tanous         {
12993ce3688aSEd Tanous             return CertificateMappingAttribute::Whole;
13003ce3688aSEd Tanous         }
13013ce3688aSEd Tanous         break;
13023ce3688aSEd Tanous         case MTLSCommonNameParseMode::UserPrincipalName:
13033ce3688aSEd Tanous         {
13043ce3688aSEd Tanous             return CertificateMappingAttribute::UserPrincipalName;
13053ce3688aSEd Tanous         }
13063ce3688aSEd Tanous         break;
13073ce3688aSEd Tanous 
13083ce3688aSEd Tanous         case MTLSCommonNameParseMode::Meta:
13093ce3688aSEd Tanous         {
13103ce3688aSEd Tanous             if constexpr (BMCWEB_META_TLS_COMMON_NAME_PARSING)
13113ce3688aSEd Tanous             {
13123ce3688aSEd Tanous                 return CertificateMappingAttribute::CommonName;
13133ce3688aSEd Tanous             }
13143ce3688aSEd Tanous         }
13153ce3688aSEd Tanous         break;
13163ce3688aSEd Tanous         default:
13173ce3688aSEd Tanous         {
13183ce3688aSEd Tanous             return CertificateMappingAttribute::Invalid;
13193ce3688aSEd Tanous         }
13203ce3688aSEd Tanous         break;
13213ce3688aSEd Tanous     }
13223ce3688aSEd Tanous }
13233ce3688aSEd Tanous 
13241aa375b8SEd Tanous inline void
13254c7d4d33SEd Tanous     handleAccountServiceGet(App& app, const crow::Request& req,
13264c7d4d33SEd Tanous                             const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
13274c7d4d33SEd Tanous {
1328afd369c6SJiaqing Zhao     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1329afd369c6SJiaqing Zhao     {
1330afd369c6SJiaqing Zhao         return;
1331afd369c6SJiaqing Zhao     }
13323e72c202SNinad Palsule 
13333e72c202SNinad Palsule     if (req.session == nullptr)
13343e72c202SNinad Palsule     {
13353e72c202SNinad Palsule         messages::internalError(asyncResp->res);
13363e72c202SNinad Palsule         return;
13373e72c202SNinad Palsule     }
13383e72c202SNinad Palsule 
1339c1019828SEd Tanous     const persistent_data::AuthConfigMethods& authMethodsConfig =
1340c1019828SEd Tanous         persistent_data::SessionStore::getInstance().getAuthMethodsConfig();
1341c1019828SEd Tanous 
1342afd369c6SJiaqing Zhao     asyncResp->res.addHeader(
1343afd369c6SJiaqing Zhao         boost::beast::http::field::link,
1344afd369c6SJiaqing Zhao         "</redfish/v1/JsonSchemas/AccountService/AccountService.json>; rel=describedby");
1345afd369c6SJiaqing Zhao 
13461476687dSEd Tanous     nlohmann::json& json = asyncResp->res.jsonValue;
13471476687dSEd Tanous     json["@odata.id"] = "/redfish/v1/AccountService";
1348482a69e7SRavi Teja     json["@odata.type"] = "#AccountService.v1_15_0.AccountService";
13491476687dSEd Tanous     json["Id"] = "AccountService";
13501476687dSEd Tanous     json["Name"] = "Account Service";
13511476687dSEd Tanous     json["Description"] = "Account Service";
13521476687dSEd Tanous     json["ServiceEnabled"] = true;
13531476687dSEd Tanous     json["MaxPasswordLength"] = 20;
13541ef4c342SEd Tanous     json["Accounts"]["@odata.id"] = "/redfish/v1/AccountService/Accounts";
13551476687dSEd Tanous     json["Roles"]["@odata.id"] = "/redfish/v1/AccountService/Roles";
1356482a69e7SRavi Teja     json["HTTPBasicAuth"] = authMethodsConfig.basic
1357482a69e7SRavi Teja                                 ? account_service::BasicAuthState::Enabled
1358482a69e7SRavi Teja                                 : account_service::BasicAuthState::Disabled;
1359482a69e7SRavi Teja 
1360482a69e7SRavi Teja     nlohmann::json::array_t allowed;
1361482a69e7SRavi Teja     allowed.emplace_back(account_service::BasicAuthState::Enabled);
1362482a69e7SRavi Teja     allowed.emplace_back(account_service::BasicAuthState::Disabled);
1363482a69e7SRavi Teja     json["HTTPBasicAuth@AllowableValues"] = std::move(allowed);
1364482a69e7SRavi Teja 
13651aa375b8SEd Tanous     nlohmann::json::object_t clientCertificate;
13661aa375b8SEd Tanous     clientCertificate["Enabled"] = authMethodsConfig.tls;
13673281bcf1SEd Tanous     clientCertificate["RespondToUnauthenticatedClients"] =
13683281bcf1SEd Tanous         !authMethodsConfig.tlsStrict;
13693ce3688aSEd Tanous 
13703ce3688aSEd Tanous     using account_service::CertificateMappingAttribute;
13713ce3688aSEd Tanous 
13723ce3688aSEd Tanous     CertificateMappingAttribute mapping =
13733ce3688aSEd Tanous         getCertificateMapping(authMethodsConfig.mTLSCommonNameParsingMode);
13743ce3688aSEd Tanous     if (mapping == CertificateMappingAttribute::Invalid)
13753ce3688aSEd Tanous     {
13763ce3688aSEd Tanous         messages::internalError(asyncResp->res);
13773ce3688aSEd Tanous     }
13783ce3688aSEd Tanous     else
13793ce3688aSEd Tanous     {
13803ce3688aSEd Tanous         clientCertificate["CertificateMappingAttribute"] = mapping;
13813ce3688aSEd Tanous     }
13821aa375b8SEd Tanous     nlohmann::json::object_t certificates;
13831aa375b8SEd Tanous     certificates["@odata.id"] =
13841aa375b8SEd Tanous         "/redfish/v1/AccountService/MultiFactorAuth/ClientCertificate/Certificates";
13851aa375b8SEd Tanous     certificates["@odata.type"] =
13861aa375b8SEd Tanous         "#CertificateCollection.CertificateCollection";
13871aa375b8SEd Tanous     clientCertificate["Certificates"] = std::move(certificates);
13881aa375b8SEd Tanous     json["MultiFactorAuth"]["ClientCertificate"] = std::move(clientCertificate);
13891aa375b8SEd Tanous 
13901aa375b8SEd Tanous     getClientCertificates(
13911aa375b8SEd Tanous         asyncResp,
13921aa375b8SEd Tanous         "/MultiFactorAuth/ClientCertificate/Certificates/Members"_json_pointer);
13931aa375b8SEd Tanous 
13941476687dSEd Tanous     json["Oem"]["OpenBMC"]["@odata.type"] =
13955b5574acSEd Tanous         "#OpenBMCAccountService.v1_0_0.AccountService";
13961476687dSEd Tanous     json["Oem"]["OpenBMC"]["@odata.id"] =
13971476687dSEd Tanous         "/redfish/v1/AccountService#/Oem/OpenBMC";
13981476687dSEd Tanous     json["Oem"]["OpenBMC"]["AuthMethods"]["BasicAuth"] =
13991476687dSEd Tanous         authMethodsConfig.basic;
14001476687dSEd Tanous     json["Oem"]["OpenBMC"]["AuthMethods"]["SessionToken"] =
14011476687dSEd Tanous         authMethodsConfig.sessionToken;
14021ef4c342SEd Tanous     json["Oem"]["OpenBMC"]["AuthMethods"]["XToken"] = authMethodsConfig.xtoken;
14031ef4c342SEd Tanous     json["Oem"]["OpenBMC"]["AuthMethods"]["Cookie"] = authMethodsConfig.cookie;
14041ef4c342SEd Tanous     json["Oem"]["OpenBMC"]["AuthMethods"]["TLS"] = authMethodsConfig.tls;
14051476687dSEd Tanous 
14061ef4c342SEd Tanous     // /redfish/v1/AccountService/LDAP/Certificates is something only
14071ef4c342SEd Tanous     // ConfigureManager can access then only display when the user has
14081ef4c342SEd Tanous     // permissions ConfigureManager
140972048780SAbhishek Patel     Privileges effectiveUserPrivileges =
14103e72c202SNinad Palsule         redfish::getUserPrivileges(*req.session);
141172048780SAbhishek Patel 
141272048780SAbhishek Patel     if (isOperationAllowedWithPrivileges({{"ConfigureManager"}},
141372048780SAbhishek Patel                                          effectiveUserPrivileges))
141472048780SAbhishek Patel     {
14151ef4c342SEd Tanous         asyncResp->res.jsonValue["LDAP"]["Certificates"]["@odata.id"] =
14161476687dSEd Tanous             "/redfish/v1/AccountService/LDAP/Certificates";
141772048780SAbhishek Patel     }
1418d1bde9e5SKrzysztof Grobelny     sdbusplus::asio::getAllProperties(
1419d1bde9e5SKrzysztof Grobelny         *crow::connections::systemBus, "xyz.openbmc_project.User.Manager",
1420d1bde9e5SKrzysztof Grobelny         "/xyz/openbmc_project/user", "xyz.openbmc_project.User.AccountPolicy",
14215e7e2dc5SEd Tanous         [asyncResp](const boost::system::error_code& ec,
14221ef4c342SEd Tanous                     const dbus::utility::DBusPropertiesMap& propertiesList) {
14233d958bbcSAppaRao Puli             if (ec)
14243d958bbcSAppaRao Puli             {
14253d958bbcSAppaRao Puli                 messages::internalError(asyncResp->res);
14263d958bbcSAppaRao Puli                 return;
14273d958bbcSAppaRao Puli             }
1428d1bde9e5SKrzysztof Grobelny 
142962598e31SEd Tanous             BMCWEB_LOG_DEBUG("Got {} properties for AccountService",
143062598e31SEd Tanous                              propertiesList.size());
1431d1bde9e5SKrzysztof Grobelny 
1432d1bde9e5SKrzysztof Grobelny             const uint8_t* minPasswordLength = nullptr;
1433d1bde9e5SKrzysztof Grobelny             const uint32_t* accountUnlockTimeout = nullptr;
1434d1bde9e5SKrzysztof Grobelny             const uint16_t* maxLoginAttemptBeforeLockout = nullptr;
1435d1bde9e5SKrzysztof Grobelny 
1436d1bde9e5SKrzysztof Grobelny             const bool success = sdbusplus::unpackPropertiesNoThrow(
1437d1bde9e5SKrzysztof Grobelny                 dbus_utils::UnpackErrorPrinter(), propertiesList,
1438d1bde9e5SKrzysztof Grobelny                 "MinPasswordLength", minPasswordLength, "AccountUnlockTimeout",
1439d1bde9e5SKrzysztof Grobelny                 accountUnlockTimeout, "MaxLoginAttemptBeforeLockout",
1440d1bde9e5SKrzysztof Grobelny                 maxLoginAttemptBeforeLockout);
1441d1bde9e5SKrzysztof Grobelny 
1442d1bde9e5SKrzysztof Grobelny             if (!success)
14433d958bbcSAppaRao Puli             {
1444d1bde9e5SKrzysztof Grobelny                 messages::internalError(asyncResp->res);
1445d1bde9e5SKrzysztof Grobelny                 return;
14463d958bbcSAppaRao Puli             }
1447d1bde9e5SKrzysztof Grobelny 
1448d1bde9e5SKrzysztof Grobelny             if (minPasswordLength != nullptr)
14493d958bbcSAppaRao Puli             {
1450bd79bce8SPatrick Williams                 asyncResp->res.jsonValue["MinPasswordLength"] =
1451bd79bce8SPatrick Williams                     *minPasswordLength;
14523d958bbcSAppaRao Puli             }
1453d1bde9e5SKrzysztof Grobelny 
1454d1bde9e5SKrzysztof Grobelny             if (accountUnlockTimeout != nullptr)
14553d958bbcSAppaRao Puli             {
1456d1bde9e5SKrzysztof Grobelny                 asyncResp->res.jsonValue["AccountLockoutDuration"] =
1457d1bde9e5SKrzysztof Grobelny                     *accountUnlockTimeout;
1458d1bde9e5SKrzysztof Grobelny             }
1459d1bde9e5SKrzysztof Grobelny 
1460d1bde9e5SKrzysztof Grobelny             if (maxLoginAttemptBeforeLockout != nullptr)
14613d958bbcSAppaRao Puli             {
1462002d39b4SEd Tanous                 asyncResp->res.jsonValue["AccountLockoutThreshold"] =
1463d1bde9e5SKrzysztof Grobelny                     *maxLoginAttemptBeforeLockout;
14643d958bbcSAppaRao Puli             }
1465d1bde9e5SKrzysztof Grobelny         });
14666973a582SRatan Gupta 
146702cad96eSEd Tanous     auto callback = [asyncResp](bool success, const LDAPConfigData& confData,
1468ab828d7cSRatan Gupta                                 const std::string& ldapType) {
1469cb13a392SEd Tanous         if (!success)
1470cb13a392SEd Tanous         {
1471cb13a392SEd Tanous             return;
1472cb13a392SEd Tanous         }
1473002d39b4SEd Tanous         parseLDAPConfigData(asyncResp->res.jsonValue, confData, ldapType);
1474ab828d7cSRatan Gupta     };
1475ab828d7cSRatan Gupta 
1476ab828d7cSRatan Gupta     getLDAPConfigData("LDAP", callback);
1477ab828d7cSRatan Gupta     getLDAPConfigData("ActiveDirectory", callback);
14781ef4c342SEd Tanous }
14796973a582SRatan Gupta 
1480bd79bce8SPatrick Williams inline void handleCertificateMappingAttributePatch(
1481bd79bce8SPatrick Williams     crow::Response& res, const std::string& certMapAttribute)
14823ce3688aSEd Tanous {
14833ce3688aSEd Tanous     MTLSCommonNameParseMode parseMode =
14843ce3688aSEd Tanous         persistent_data::getMTLSCommonNameParseMode(certMapAttribute);
14853ce3688aSEd Tanous     if (parseMode == MTLSCommonNameParseMode::Invalid)
14863ce3688aSEd Tanous     {
14873ce3688aSEd Tanous         messages::propertyValueNotInList(res, "CertificateMappingAttribute",
14883ce3688aSEd Tanous                                          certMapAttribute);
14893ce3688aSEd Tanous         return;
14903ce3688aSEd Tanous     }
14913ce3688aSEd Tanous 
14923ce3688aSEd Tanous     persistent_data::AuthConfigMethods& authMethodsConfig =
14933ce3688aSEd Tanous         persistent_data::SessionStore::getInstance().getAuthMethodsConfig();
14943ce3688aSEd Tanous     authMethodsConfig.mTLSCommonNameParsingMode = parseMode;
14953ce3688aSEd Tanous }
14963ce3688aSEd Tanous 
14973281bcf1SEd Tanous inline void handleRespondToUnauthenticatedClientsPatch(
14983281bcf1SEd Tanous     App& app, const crow::Request& req, crow::Response& res,
14993281bcf1SEd Tanous     bool respondToUnauthenticatedClients)
15003281bcf1SEd Tanous {
15013281bcf1SEd Tanous     if (req.session != nullptr)
15023281bcf1SEd Tanous     {
15033281bcf1SEd Tanous         // Sanity check.  If the user isn't currently authenticated with mutual
15043281bcf1SEd Tanous         // TLS, they very likely are about to permanently lock themselves out.
15053281bcf1SEd Tanous         // Make sure they're using mutual TLS before allowing locking.
15063281bcf1SEd Tanous         if (req.session->sessionType != persistent_data::SessionType::MutualTLS)
15073281bcf1SEd Tanous         {
15083281bcf1SEd Tanous             messages::propertyValueExternalConflict(
15093281bcf1SEd Tanous                 res,
15103281bcf1SEd Tanous                 "MultiFactorAuth/ClientCertificate/RespondToUnauthenticatedClients",
15113281bcf1SEd Tanous                 respondToUnauthenticatedClients);
15123281bcf1SEd Tanous             return;
15133281bcf1SEd Tanous         }
15143281bcf1SEd Tanous     }
15153281bcf1SEd Tanous 
15163281bcf1SEd Tanous     persistent_data::AuthConfigMethods& authMethodsConfig =
15173281bcf1SEd Tanous         persistent_data::SessionStore::getInstance().getAuthMethodsConfig();
15183281bcf1SEd Tanous 
15193281bcf1SEd Tanous     // Change the settings
15203281bcf1SEd Tanous     authMethodsConfig.tlsStrict = !respondToUnauthenticatedClients;
15213281bcf1SEd Tanous 
15223281bcf1SEd Tanous     // Write settings to disk
15233281bcf1SEd Tanous     persistent_data::getConfig().writeData();
15243281bcf1SEd Tanous 
15253281bcf1SEd Tanous     // Trigger a reload, to apply the new settings to new connections
15263281bcf1SEd Tanous     app.loadCertificate();
15273281bcf1SEd Tanous }
15283281bcf1SEd Tanous 
15291ef4c342SEd Tanous inline void handleAccountServicePatch(
15301ef4c342SEd Tanous     App& app, const crow::Request& req,
15311ef4c342SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
15321ef4c342SEd Tanous {
15333ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
153445ca1b86SEd Tanous     {
153545ca1b86SEd Tanous         return;
153645ca1b86SEd Tanous     }
1537f5ffd806SEd Tanous     std::optional<uint32_t> unlockTimeout;
1538f5ffd806SEd Tanous     std::optional<uint16_t> lockoutThreshold;
1539ef73ad0dSPaul Fertser     std::optional<uint8_t> minPasswordLength;
1540f5ffd806SEd Tanous     std::optional<uint16_t> maxPasswordLength;
154110cb44f3SEd Tanous     LdapPatchParams ldapObject;
15423ce3688aSEd Tanous     std::optional<std::string> certificateMappingAttribute;
15433281bcf1SEd Tanous     std::optional<bool> respondToUnauthenticatedClients;
154410cb44f3SEd Tanous     LdapPatchParams activeDirectoryObject;
1545c1019828SEd Tanous     AuthMethods auth;
1546482a69e7SRavi Teja     std::optional<std::string> httpBasicAuth;
15473ce3688aSEd Tanous 
1548*afc474aeSMyung Bae     if (!json_util::readJsonPatch( //
1549*afc474aeSMyung Bae             req, asyncResp->res, //
1550*afc474aeSMyung Bae             "AccountLockoutDuration", unlockTimeout, //
1551*afc474aeSMyung Bae             "AccountLockoutThreshold", lockoutThreshold, //
1552*afc474aeSMyung Bae             "ActiveDirectory/Authentication/AuthenticationType",
1553*afc474aeSMyung Bae             activeDirectoryObject.authType, //
1554*afc474aeSMyung Bae             "ActiveDirectory/Authentication/Password",
1555*afc474aeSMyung Bae             activeDirectoryObject.password, //
1556*afc474aeSMyung Bae             "ActiveDirectory/Authentication/Username",
1557*afc474aeSMyung Bae             activeDirectoryObject.userName, //
1558*afc474aeSMyung Bae             "ActiveDirectory/LDAPService/SearchSettings/BaseDistinguishedNames",
1559*afc474aeSMyung Bae             activeDirectoryObject.baseDNList, //
1560*afc474aeSMyung Bae             "ActiveDirectory/LDAPService/SearchSettings/GroupsAttribute",
1561*afc474aeSMyung Bae             activeDirectoryObject.groupsAttribute, //
1562*afc474aeSMyung Bae             "ActiveDirectory/LDAPService/SearchSettings/UsernameAttribute",
1563*afc474aeSMyung Bae             activeDirectoryObject.userNameAttribute, //
1564*afc474aeSMyung Bae             "ActiveDirectory/RemoteRoleMapping",
1565*afc474aeSMyung Bae             activeDirectoryObject.remoteRoleMapData, //
1566*afc474aeSMyung Bae             "ActiveDirectory/ServiceAddresses",
1567*afc474aeSMyung Bae             activeDirectoryObject.serviceAddressList, //
1568*afc474aeSMyung Bae             "ActiveDirectory/ServiceEnabled",
1569*afc474aeSMyung Bae             activeDirectoryObject.serviceEnabled, //
1570*afc474aeSMyung Bae             "HTTPBasicAuth", httpBasicAuth, //
1571*afc474aeSMyung Bae             "LDAP/Authentication/AuthenticationType", ldapObject.authType, //
1572*afc474aeSMyung Bae             "LDAP/Authentication/Password", ldapObject.password, //
1573*afc474aeSMyung Bae             "LDAP/Authentication/Username", ldapObject.userName, //
1574*afc474aeSMyung Bae             "LDAP/LDAPService/SearchSettings/BaseDistinguishedNames",
1575*afc474aeSMyung Bae             ldapObject.baseDNList, //
1576*afc474aeSMyung Bae             "LDAP/LDAPService/SearchSettings/GroupsAttribute",
1577*afc474aeSMyung Bae             ldapObject.groupsAttribute, //
1578*afc474aeSMyung Bae             "LDAP/LDAPService/SearchSettings/UsernameAttribute",
1579*afc474aeSMyung Bae             ldapObject.userNameAttribute, //
1580*afc474aeSMyung Bae             "LDAP/RemoteRoleMapping", ldapObject.remoteRoleMapData, //
1581*afc474aeSMyung Bae             "LDAP/ServiceAddresses", ldapObject.serviceAddressList, //
1582*afc474aeSMyung Bae             "LDAP/ServiceEnabled", ldapObject.serviceEnabled, //
1583*afc474aeSMyung Bae             "MaxPasswordLength", maxPasswordLength, //
1584*afc474aeSMyung Bae             "MinPasswordLength", minPasswordLength, //
1585*afc474aeSMyung Bae             "MultiFactorAuth/ClientCertificate/CertificateMappingAttribute",
1586*afc474aeSMyung Bae             certificateMappingAttribute, //
1587*afc474aeSMyung Bae             "MultiFactorAuth/ClientCertificate/RespondToUnauthenticatedClients",
1588*afc474aeSMyung Bae             respondToUnauthenticatedClients, //
1589*afc474aeSMyung Bae             "Oem/OpenBMC/AuthMethods/BasicAuth", auth.basicAuth, //
1590*afc474aeSMyung Bae             "Oem/OpenBMC/AuthMethods/Cookie", auth.cookie, //
1591*afc474aeSMyung Bae             "Oem/OpenBMC/AuthMethods/SessionToken", auth.sessionToken, //
1592*afc474aeSMyung Bae             "Oem/OpenBMC/AuthMethods/TLS", auth.tls, //
1593*afc474aeSMyung Bae             "Oem/OpenBMC/AuthMethods/XToken", auth.xToken //
1594*afc474aeSMyung Bae             ))
1595f5ffd806SEd Tanous     {
1596f5ffd806SEd Tanous         return;
1597f5ffd806SEd Tanous     }
1598f5ffd806SEd Tanous 
1599482a69e7SRavi Teja     if (httpBasicAuth)
1600482a69e7SRavi Teja     {
1601482a69e7SRavi Teja         if (*httpBasicAuth == "Enabled")
1602482a69e7SRavi Teja         {
1603482a69e7SRavi Teja             auth.basicAuth = true;
1604482a69e7SRavi Teja         }
1605482a69e7SRavi Teja         else if (*httpBasicAuth == "Disabled")
1606482a69e7SRavi Teja         {
1607482a69e7SRavi Teja             auth.basicAuth = false;
1608482a69e7SRavi Teja         }
1609482a69e7SRavi Teja         else
1610482a69e7SRavi Teja         {
1611482a69e7SRavi Teja             messages::propertyValueNotInList(asyncResp->res, "HttpBasicAuth",
1612482a69e7SRavi Teja                                              *httpBasicAuth);
1613482a69e7SRavi Teja         }
1614482a69e7SRavi Teja     }
1615482a69e7SRavi Teja 
16163281bcf1SEd Tanous     if (respondToUnauthenticatedClients)
16173281bcf1SEd Tanous     {
16183281bcf1SEd Tanous         handleRespondToUnauthenticatedClientsPatch(
16193281bcf1SEd Tanous             app, req, asyncResp->res, *respondToUnauthenticatedClients);
16203281bcf1SEd Tanous     }
16213281bcf1SEd Tanous 
16223ce3688aSEd Tanous     if (certificateMappingAttribute)
16233ce3688aSEd Tanous     {
16243ce3688aSEd Tanous         handleCertificateMappingAttributePatch(asyncResp->res,
16253ce3688aSEd Tanous                                                *certificateMappingAttribute);
16263ce3688aSEd Tanous     }
16273ce3688aSEd Tanous 
1628f5ffd806SEd Tanous     if (minPasswordLength)
1629f5ffd806SEd Tanous     {
1630d02aad39SEd Tanous         setDbusProperty(
1631e93abac6SGinu George             asyncResp, "MinPasswordLength", "xyz.openbmc_project.User.Manager",
1632d02aad39SEd Tanous             sdbusplus::message::object_path("/xyz/openbmc_project/user"),
16339ae226faSGeorge Liu             "xyz.openbmc_project.User.AccountPolicy", "MinPasswordLength",
1634e93abac6SGinu George             *minPasswordLength);
1635f5ffd806SEd Tanous     }
1636f5ffd806SEd Tanous 
1637f5ffd806SEd Tanous     if (maxPasswordLength)
1638f5ffd806SEd Tanous     {
16391ef4c342SEd Tanous         messages::propertyNotWritable(asyncResp->res, "MaxPasswordLength");
1640f5ffd806SEd Tanous     }
1641f5ffd806SEd Tanous 
164210cb44f3SEd Tanous     handleLDAPPatch(std::move(activeDirectoryObject), asyncResp,
164310cb44f3SEd Tanous                     "ActiveDirectory");
164410cb44f3SEd Tanous     handleLDAPPatch(std::move(ldapObject), asyncResp, "LDAP");
1645f5ffd806SEd Tanous 
1646c1019828SEd Tanous     handleAuthMethodsPatch(asyncResp, auth);
1647f5ffd806SEd Tanous 
1648f5ffd806SEd Tanous     if (unlockTimeout)
1649f5ffd806SEd Tanous     {
1650d02aad39SEd Tanous         setDbusProperty(
1651e93abac6SGinu George             asyncResp, "AccountLockoutDuration",
1652e93abac6SGinu George             "xyz.openbmc_project.User.Manager",
1653d02aad39SEd Tanous             sdbusplus::message::object_path("/xyz/openbmc_project/user"),
16549ae226faSGeorge Liu             "xyz.openbmc_project.User.AccountPolicy", "AccountUnlockTimeout",
1655e93abac6SGinu George             *unlockTimeout);
1656f5ffd806SEd Tanous     }
1657f5ffd806SEd Tanous     if (lockoutThreshold)
1658f5ffd806SEd Tanous     {
1659d02aad39SEd Tanous         setDbusProperty(
1660e93abac6SGinu George             asyncResp, "AccountLockoutThreshold",
1661e93abac6SGinu George             "xyz.openbmc_project.User.Manager",
1662d02aad39SEd Tanous             sdbusplus::message::object_path("/xyz/openbmc_project/user"),
16639ae226faSGeorge Liu             "xyz.openbmc_project.User.AccountPolicy",
1664e93abac6SGinu George             "MaxLoginAttemptBeforeLockout", *lockoutThreshold);
1665f5ffd806SEd Tanous     }
16661ef4c342SEd Tanous }
1667f5ffd806SEd Tanous 
16684c7d4d33SEd Tanous inline void handleAccountCollectionHead(
16691ef4c342SEd Tanous     App& app, const crow::Request& req,
16701ef4c342SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
16711ef4c342SEd Tanous {
16723ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
167345ca1b86SEd Tanous     {
167445ca1b86SEd Tanous         return;
167545ca1b86SEd Tanous     }
16764c7d4d33SEd Tanous     asyncResp->res.addHeader(
16774c7d4d33SEd Tanous         boost::beast::http::field::link,
16784c7d4d33SEd Tanous         "</redfish/v1/JsonSchemas/ManagerAccountCollection.json>; rel=describedby");
16794c7d4d33SEd Tanous }
16804c7d4d33SEd Tanous 
16814c7d4d33SEd Tanous inline void handleAccountCollectionGet(
16824c7d4d33SEd Tanous     App& app, const crow::Request& req,
16834c7d4d33SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
16844c7d4d33SEd Tanous {
1685afd369c6SJiaqing Zhao     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1686afd369c6SJiaqing Zhao     {
1687afd369c6SJiaqing Zhao         return;
1688afd369c6SJiaqing Zhao     }
16893e72c202SNinad Palsule 
16903e72c202SNinad Palsule     if (req.session == nullptr)
16913e72c202SNinad Palsule     {
16923e72c202SNinad Palsule         messages::internalError(asyncResp->res);
16933e72c202SNinad Palsule         return;
16943e72c202SNinad Palsule     }
16953e72c202SNinad Palsule 
1696afd369c6SJiaqing Zhao     asyncResp->res.addHeader(
1697afd369c6SJiaqing Zhao         boost::beast::http::field::link,
1698afd369c6SJiaqing Zhao         "</redfish/v1/JsonSchemas/ManagerAccountCollection.json>; rel=describedby");
16991476687dSEd Tanous 
17001476687dSEd Tanous     asyncResp->res.jsonValue["@odata.id"] =
17011476687dSEd Tanous         "/redfish/v1/AccountService/Accounts";
17021ef4c342SEd Tanous     asyncResp->res.jsonValue["@odata.type"] = "#ManagerAccountCollection."
17031476687dSEd Tanous                                               "ManagerAccountCollection";
17041476687dSEd Tanous     asyncResp->res.jsonValue["Name"] = "Accounts Collection";
17051476687dSEd Tanous     asyncResp->res.jsonValue["Description"] = "BMC User Accounts";
17060f74e643SEd Tanous 
17076c51eab1SEd Tanous     Privileges effectiveUserPrivileges =
17083e72c202SNinad Palsule         redfish::getUserPrivileges(*req.session);
17096c51eab1SEd Tanous 
1710f5e29f33SJunLin Chen     std::string thisUser;
1711f5e29f33SJunLin Chen     if (req.session)
1712f5e29f33SJunLin Chen     {
1713f5e29f33SJunLin Chen         thisUser = req.session->username;
1714f5e29f33SJunLin Chen     }
17155eb468daSGeorge Liu     sdbusplus::message::object_path path("/xyz/openbmc_project/user");
17165eb468daSGeorge Liu     dbus::utility::getManagedObjects(
17175eb468daSGeorge Liu         "xyz.openbmc_project.User.Manager", path,
1718cef1ddfbSEd Tanous         [asyncResp, thisUser, effectiveUserPrivileges](
17195e7e2dc5SEd Tanous             const boost::system::error_code& ec,
1720711ac7a9SEd Tanous             const dbus::utility::ManagedObjectType& users) {
1721b9b2e0b2SEd Tanous             if (ec)
1722b9b2e0b2SEd Tanous             {
1723f12894f8SJason M. Bills                 messages::internalError(asyncResp->res);
1724b9b2e0b2SEd Tanous                 return;
1725b9b2e0b2SEd Tanous             }
1726b9b2e0b2SEd Tanous 
1727cef1ddfbSEd Tanous             bool userCanSeeAllAccounts =
1728002d39b4SEd Tanous                 effectiveUserPrivileges.isSupersetOf({"ConfigureUsers"});
1729cef1ddfbSEd Tanous 
1730cef1ddfbSEd Tanous             bool userCanSeeSelf =
1731002d39b4SEd Tanous                 effectiveUserPrivileges.isSupersetOf({"ConfigureSelf"});
1732cef1ddfbSEd Tanous 
1733002d39b4SEd Tanous             nlohmann::json& memberArray = asyncResp->res.jsonValue["Members"];
1734b9b2e0b2SEd Tanous             memberArray = nlohmann::json::array();
1735b9b2e0b2SEd Tanous 
17369eb808c1SEd Tanous             for (const auto& userpath : users)
1737b9b2e0b2SEd Tanous             {
17382dfd18efSEd Tanous                 std::string user = userpath.first.filename();
17392dfd18efSEd Tanous                 if (user.empty())
1740b9b2e0b2SEd Tanous                 {
17412dfd18efSEd Tanous                     messages::internalError(asyncResp->res);
174262598e31SEd Tanous                     BMCWEB_LOG_ERROR("Invalid firmware ID");
17432dfd18efSEd Tanous 
17442dfd18efSEd Tanous                     return;
1745b9b2e0b2SEd Tanous                 }
1746f365910cSGunnar Mills 
1747f365910cSGunnar Mills                 // As clarified by Redfish here:
1748f365910cSGunnar Mills                 // https://redfishforum.com/thread/281/manageraccountcollection-change-allows-account-enumeration
17496c51eab1SEd Tanous                 // Users without ConfigureUsers, only see their own
17506c51eab1SEd Tanous                 // account. Users with ConfigureUsers, see all
17516c51eab1SEd Tanous                 // accounts.
1752bd79bce8SPatrick Williams                 if (userCanSeeAllAccounts ||
1753bd79bce8SPatrick Williams                     (thisUser == user && userCanSeeSelf))
1754f365910cSGunnar Mills                 {
17551476687dSEd Tanous                     nlohmann::json::object_t member;
17563b32780dSEd Tanous                     member["@odata.id"] = boost::urls::format(
17573b32780dSEd Tanous                         "/redfish/v1/AccountService/Accounts/{}", user);
1758b2ba3072SPatrick Williams                     memberArray.emplace_back(std::move(member));
1759b9b2e0b2SEd Tanous                 }
1760f365910cSGunnar Mills             }
1761bd79bce8SPatrick Williams             asyncResp->res.jsonValue["Members@odata.count"] =
1762bd79bce8SPatrick Williams                 memberArray.size();
17635eb468daSGeorge Liu         });
17641ef4c342SEd Tanous }
17656c51eab1SEd Tanous 
176697e90da3SNinad Palsule inline void processAfterCreateUser(
176797e90da3SNinad Palsule     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
176897e90da3SNinad Palsule     const std::string& username, const std::string& password,
176997e90da3SNinad Palsule     const boost::system::error_code& ec, sdbusplus::message_t& m)
177097e90da3SNinad Palsule {
177197e90da3SNinad Palsule     if (ec)
177297e90da3SNinad Palsule     {
177397e90da3SNinad Palsule         userErrorMessageHandler(m.get_error(), asyncResp, username, "");
177497e90da3SNinad Palsule         return;
177597e90da3SNinad Palsule     }
177697e90da3SNinad Palsule 
177797e90da3SNinad Palsule     if (pamUpdatePassword(username, password) != PAM_SUCCESS)
177897e90da3SNinad Palsule     {
177997e90da3SNinad Palsule         // At this point we have a user that's been
178097e90da3SNinad Palsule         // created, but the password set
178197e90da3SNinad Palsule         // failed.Something is wrong, so delete the user
178297e90da3SNinad Palsule         // that we've already created
178397e90da3SNinad Palsule         sdbusplus::message::object_path tempObjPath(rootUserDbusPath);
178497e90da3SNinad Palsule         tempObjPath /= username;
178597e90da3SNinad Palsule         const std::string userPath(tempObjPath);
178697e90da3SNinad Palsule 
178797e90da3SNinad Palsule         crow::connections::systemBus->async_method_call(
178897e90da3SNinad Palsule             [asyncResp, password](const boost::system::error_code& ec3) {
178997e90da3SNinad Palsule                 if (ec3)
179097e90da3SNinad Palsule                 {
179197e90da3SNinad Palsule                     messages::internalError(asyncResp->res);
179297e90da3SNinad Palsule                     return;
179397e90da3SNinad Palsule                 }
179497e90da3SNinad Palsule 
179597e90da3SNinad Palsule                 // If password is invalid
17969bd80831SJason M. Bills                 messages::propertyValueFormatError(asyncResp->res, nullptr,
179797e90da3SNinad Palsule                                                    "Password");
179897e90da3SNinad Palsule             },
179997e90da3SNinad Palsule             "xyz.openbmc_project.User.Manager", userPath,
180097e90da3SNinad Palsule             "xyz.openbmc_project.Object.Delete", "Delete");
180197e90da3SNinad Palsule 
180262598e31SEd Tanous         BMCWEB_LOG_ERROR("pamUpdatePassword Failed");
180397e90da3SNinad Palsule         return;
180497e90da3SNinad Palsule     }
180597e90da3SNinad Palsule 
180697e90da3SNinad Palsule     messages::created(asyncResp->res);
180797e90da3SNinad Palsule     asyncResp->res.addHeader("Location",
180897e90da3SNinad Palsule                              "/redfish/v1/AccountService/Accounts/" + username);
180997e90da3SNinad Palsule }
181097e90da3SNinad Palsule 
181197e90da3SNinad Palsule inline void processAfterGetAllGroups(
181297e90da3SNinad Palsule     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
181397e90da3SNinad Palsule     const std::string& username, const std::string& password,
1814e01d0c36SEd Tanous     const std::string& roleId, bool enabled,
18159ba73934SNinad Palsule     std::optional<std::vector<std::string>> accountTypes,
181697e90da3SNinad Palsule     const std::vector<std::string>& allGroupsList)
181797e90da3SNinad Palsule {
18183e72c202SNinad Palsule     std::vector<std::string> userGroups;
18199ba73934SNinad Palsule     std::vector<std::string> accountTypeUserGroups;
18209ba73934SNinad Palsule 
18219ba73934SNinad Palsule     // If user specified account types then convert them to unix user groups
18229ba73934SNinad Palsule     if (accountTypes)
18239ba73934SNinad Palsule     {
18249ba73934SNinad Palsule         if (!getUserGroupFromAccountType(asyncResp->res, *accountTypes,
18259ba73934SNinad Palsule                                          accountTypeUserGroups))
18269ba73934SNinad Palsule         {
18279ba73934SNinad Palsule             // Problem in mapping Account Types to User Groups, Error already
18289ba73934SNinad Palsule             // logged.
18299ba73934SNinad Palsule             return;
18309ba73934SNinad Palsule         }
18319ba73934SNinad Palsule     }
18329ba73934SNinad Palsule 
18333e72c202SNinad Palsule     for (const auto& grp : allGroupsList)
18343e72c202SNinad Palsule     {
18359ba73934SNinad Palsule         // If user specified the account type then only accept groups which are
18369ba73934SNinad Palsule         // in the account types group list.
18379ba73934SNinad Palsule         if (!accountTypeUserGroups.empty())
18389ba73934SNinad Palsule         {
18399ba73934SNinad Palsule             bool found = false;
18409ba73934SNinad Palsule             for (const auto& grp1 : accountTypeUserGroups)
18419ba73934SNinad Palsule             {
18429ba73934SNinad Palsule                 if (grp == grp1)
18439ba73934SNinad Palsule                 {
18449ba73934SNinad Palsule                     found = true;
18459ba73934SNinad Palsule                     break;
18469ba73934SNinad Palsule                 }
18479ba73934SNinad Palsule             }
18489ba73934SNinad Palsule             if (!found)
18499ba73934SNinad Palsule             {
18509ba73934SNinad Palsule                 continue;
18519ba73934SNinad Palsule             }
18529ba73934SNinad Palsule         }
18539ba73934SNinad Palsule 
18543e72c202SNinad Palsule         // Console access is provided to the user who is a member of
18553e72c202SNinad Palsule         // hostconsole group and has a administrator role. So, set
18563e72c202SNinad Palsule         // hostconsole group only for the administrator.
18579ba73934SNinad Palsule         if ((grp == "hostconsole") && (roleId != "priv-admin"))
18583e72c202SNinad Palsule         {
18599ba73934SNinad Palsule             if (!accountTypeUserGroups.empty())
18609ba73934SNinad Palsule             {
186162598e31SEd Tanous                 BMCWEB_LOG_ERROR(
186262598e31SEd Tanous                     "Only administrator can get HostConsole access");
18639ba73934SNinad Palsule                 asyncResp->res.result(boost::beast::http::status::bad_request);
18649ba73934SNinad Palsule                 return;
18659ba73934SNinad Palsule             }
18669ba73934SNinad Palsule             continue;
18679ba73934SNinad Palsule         }
18683e72c202SNinad Palsule         userGroups.emplace_back(grp);
18693e72c202SNinad Palsule     }
18709ba73934SNinad Palsule 
18719ba73934SNinad Palsule     // Make sure user specified groups are valid. This is internal error because
18729ba73934SNinad Palsule     // it some inconsistencies between user manager and bmcweb.
18739ba73934SNinad Palsule     if (!accountTypeUserGroups.empty() &&
18749ba73934SNinad Palsule         accountTypeUserGroups.size() != userGroups.size())
18759ba73934SNinad Palsule     {
18769ba73934SNinad Palsule         messages::internalError(asyncResp->res);
18779ba73934SNinad Palsule         return;
18783e72c202SNinad Palsule     }
187997e90da3SNinad Palsule     crow::connections::systemBus->async_method_call(
188097e90da3SNinad Palsule         [asyncResp, username, password](const boost::system::error_code& ec2,
188197e90da3SNinad Palsule                                         sdbusplus::message_t& m) {
188297e90da3SNinad Palsule             processAfterCreateUser(asyncResp, username, password, ec2, m);
188397e90da3SNinad Palsule         },
188497e90da3SNinad Palsule         "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
18853e72c202SNinad Palsule         "xyz.openbmc_project.User.Manager", "CreateUser", username, userGroups,
1886e01d0c36SEd Tanous         roleId, enabled);
188797e90da3SNinad Palsule }
188897e90da3SNinad Palsule 
18891ef4c342SEd Tanous inline void handleAccountCollectionPost(
18901ef4c342SEd Tanous     App& app, const crow::Request& req,
18911ef4c342SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
18921ef4c342SEd Tanous {
18933ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
189445ca1b86SEd Tanous     {
189545ca1b86SEd Tanous         return;
189645ca1b86SEd Tanous     }
18979712f8acSEd Tanous     std::string username;
18989712f8acSEd Tanous     std::string password;
1899e01d0c36SEd Tanous     std::optional<std::string> roleIdJson;
1900e01d0c36SEd Tanous     std::optional<bool> enabledJson;
19019ba73934SNinad Palsule     std::optional<std::vector<std::string>> accountTypes;
1902*afc474aeSMyung Bae     if (!json_util::readJsonPatch( //
1903*afc474aeSMyung Bae             req, asyncResp->res, //
1904*afc474aeSMyung Bae             "AccountTypes", accountTypes, //
1905*afc474aeSMyung Bae             "Enabled", enabledJson, //
1906*afc474aeSMyung Bae             "Password", password, //
1907*afc474aeSMyung Bae             "RoleId", roleIdJson, //
1908*afc474aeSMyung Bae             "UserName", username //
1909*afc474aeSMyung Bae             ))
191004ae99ecSEd Tanous     {
191104ae99ecSEd Tanous         return;
191204ae99ecSEd Tanous     }
191304ae99ecSEd Tanous 
1914e01d0c36SEd Tanous     std::string roleId = roleIdJson.value_or("User");
1915e01d0c36SEd Tanous     std::string priv = getPrivilegeFromRoleId(roleId);
191684e12cb7SAppaRao Puli     if (priv.empty())
191704ae99ecSEd Tanous     {
1918e01d0c36SEd Tanous         messages::propertyValueNotInList(asyncResp->res, roleId, "RoleId");
191904ae99ecSEd Tanous         return;
192004ae99ecSEd Tanous     }
19219712f8acSEd Tanous     roleId = priv;
192204ae99ecSEd Tanous 
1923e01d0c36SEd Tanous     bool enabled = enabledJson.value_or(true);
1924e01d0c36SEd Tanous 
1925599c71d8SAyushi Smriti     // Reading AllGroups property
19261e1e598dSJonathan Doman     sdbusplus::asio::getProperty<std::vector<std::string>>(
19271ef4c342SEd Tanous         *crow::connections::systemBus, "xyz.openbmc_project.User.Manager",
19281ef4c342SEd Tanous         "/xyz/openbmc_project/user", "xyz.openbmc_project.User.Manager",
19291ef4c342SEd Tanous         "AllGroups",
19309ba73934SNinad Palsule         [asyncResp, username, password{std::move(password)}, roleId, enabled,
19319ba73934SNinad Palsule          accountTypes](const boost::system::error_code& ec,
19321e1e598dSJonathan Doman                        const std::vector<std::string>& allGroupsList) {
1933599c71d8SAyushi Smriti             if (ec)
1934599c71d8SAyushi Smriti             {
1935a0735a4eSGunnar Mills                 BMCWEB_LOG_ERROR("D-Bus response error {}", ec);
1936599c71d8SAyushi Smriti                 messages::internalError(asyncResp->res);
1937599c71d8SAyushi Smriti                 return;
1938599c71d8SAyushi Smriti             }
1939599c71d8SAyushi Smriti 
19401e1e598dSJonathan Doman             if (allGroupsList.empty())
1941599c71d8SAyushi Smriti             {
1942599c71d8SAyushi Smriti                 messages::internalError(asyncResp->res);
1943599c71d8SAyushi Smriti                 return;
1944599c71d8SAyushi Smriti             }
1945599c71d8SAyushi Smriti 
1946bd79bce8SPatrick Williams             processAfterGetAllGroups(asyncResp, username, password, roleId,
1947bd79bce8SPatrick Williams                                      enabled, accountTypes, allGroupsList);
19481e1e598dSJonathan Doman         });
19491ef4c342SEd Tanous }
1950b9b2e0b2SEd Tanous 
19511ef4c342SEd Tanous inline void
19524c7d4d33SEd Tanous     handleAccountHead(App& app, const crow::Request& req,
19536c51eab1SEd Tanous                       const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
19544c7d4d33SEd Tanous                       const std::string& /*accountName*/)
19551ef4c342SEd Tanous {
19563ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
195745ca1b86SEd Tanous     {
195845ca1b86SEd Tanous         return;
195945ca1b86SEd Tanous     }
19604c7d4d33SEd Tanous     asyncResp->res.addHeader(
19614c7d4d33SEd Tanous         boost::beast::http::field::link,
19624c7d4d33SEd Tanous         "</redfish/v1/JsonSchemas/ManagerAccount/ManagerAccount.json>; rel=describedby");
19634c7d4d33SEd Tanous }
1964afd369c6SJiaqing Zhao 
19654c7d4d33SEd Tanous inline void
19664c7d4d33SEd Tanous     handleAccountGet(App& app, const crow::Request& req,
19674c7d4d33SEd Tanous                      const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
19684c7d4d33SEd Tanous                      const std::string& accountName)
19694c7d4d33SEd Tanous {
1970afd369c6SJiaqing Zhao     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1971afd369c6SJiaqing Zhao     {
1972afd369c6SJiaqing Zhao         return;
1973afd369c6SJiaqing Zhao     }
1974afd369c6SJiaqing Zhao     asyncResp->res.addHeader(
1975afd369c6SJiaqing Zhao         boost::beast::http::field::link,
1976afd369c6SJiaqing Zhao         "</redfish/v1/JsonSchemas/ManagerAccount/ManagerAccount.json>; rel=describedby");
1977afd369c6SJiaqing Zhao 
197825b54dbaSEd Tanous     if constexpr (BMCWEB_INSECURE_DISABLE_AUTH)
197925b54dbaSEd Tanous     {
1980031514fbSJunLin Chen         // If authentication is disabled, there are no user accounts
198125b54dbaSEd Tanous         messages::resourceNotFound(asyncResp->res, "ManagerAccount",
198225b54dbaSEd Tanous                                    accountName);
1983031514fbSJunLin Chen         return;
198425b54dbaSEd Tanous     }
1985afd369c6SJiaqing Zhao 
1986031514fbSJunLin Chen     if (req.session == nullptr)
1987031514fbSJunLin Chen     {
1988031514fbSJunLin Chen         messages::internalError(asyncResp->res);
1989031514fbSJunLin Chen         return;
1990031514fbSJunLin Chen     }
19916c51eab1SEd Tanous     if (req.session->username != accountName)
1992b9b2e0b2SEd Tanous     {
19936c51eab1SEd Tanous         // At this point we've determined that the user is trying to
19941ef4c342SEd Tanous         // modify a user that isn't them.  We need to verify that they
19951ef4c342SEd Tanous         // have permissions to modify other users, so re-run the auth
19961ef4c342SEd Tanous         // check with the same permissions, minus ConfigureSelf.
19976c51eab1SEd Tanous         Privileges effectiveUserPrivileges =
19983e72c202SNinad Palsule             redfish::getUserPrivileges(*req.session);
19991ef4c342SEd Tanous         Privileges requiredPermissionsToChangeNonSelf = {"ConfigureUsers",
20001ef4c342SEd Tanous                                                          "ConfigureManager"};
20016c51eab1SEd Tanous         if (!effectiveUserPrivileges.isSupersetOf(
20026c51eab1SEd Tanous                 requiredPermissionsToChangeNonSelf))
2003900f9497SJoseph Reynolds         {
200462598e31SEd Tanous             BMCWEB_LOG_DEBUG("GET Account denied access");
2005900f9497SJoseph Reynolds             messages::insufficientPrivilege(asyncResp->res);
2006900f9497SJoseph Reynolds             return;
2007900f9497SJoseph Reynolds         }
2008900f9497SJoseph Reynolds     }
2009900f9497SJoseph Reynolds 
20105eb468daSGeorge Liu     sdbusplus::message::object_path path("/xyz/openbmc_project/user");
20115eb468daSGeorge Liu     dbus::utility::getManagedObjects(
20125eb468daSGeorge Liu         "xyz.openbmc_project.User.Manager", path,
20131ef4c342SEd Tanous         [asyncResp,
20145e7e2dc5SEd Tanous          accountName](const boost::system::error_code& ec,
2015711ac7a9SEd Tanous                       const dbus::utility::ManagedObjectType& users) {
2016b9b2e0b2SEd Tanous             if (ec)
2017b9b2e0b2SEd Tanous             {
2018f12894f8SJason M. Bills                 messages::internalError(asyncResp->res);
2019b9b2e0b2SEd Tanous                 return;
2020b9b2e0b2SEd Tanous             }
20213544d2a7SEd Tanous             const auto userIt = std::ranges::find_if(
202280f79a40SMichael Shen                 users,
202380f79a40SMichael Shen                 [accountName](
2024b477fd44SP Dheeraj Srujan Kumar                     const std::pair<sdbusplus::message::object_path,
202580f79a40SMichael Shen                                     dbus::utility::DBusInterfacesMap>& user) {
202655f79e6fSEd Tanous                     return accountName == user.first.filename();
2027b477fd44SP Dheeraj Srujan Kumar                 });
2028b9b2e0b2SEd Tanous 
202984e12cb7SAppaRao Puli             if (userIt == users.end())
2030b9b2e0b2SEd Tanous             {
2031002d39b4SEd Tanous                 messages::resourceNotFound(asyncResp->res, "ManagerAccount",
2032002d39b4SEd Tanous                                            accountName);
203384e12cb7SAppaRao Puli                 return;
203484e12cb7SAppaRao Puli             }
20354e68c45bSAyushi Smriti 
20361476687dSEd Tanous             asyncResp->res.jsonValue["@odata.type"] =
203758345856SAbhishek Patel                 "#ManagerAccount.v1_7_0.ManagerAccount";
20381476687dSEd Tanous             asyncResp->res.jsonValue["Name"] = "User Account";
20391476687dSEd Tanous             asyncResp->res.jsonValue["Description"] = "User Account";
20401476687dSEd Tanous             asyncResp->res.jsonValue["Password"] = nullptr;
204158345856SAbhishek Patel             asyncResp->res.jsonValue["StrictAccountTypes"] = true;
20424e68c45bSAyushi Smriti 
204384e12cb7SAppaRao Puli             for (const auto& interface : userIt->second)
204465b0dc32SEd Tanous             {
2045002d39b4SEd Tanous                 if (interface.first == "xyz.openbmc_project.User.Attributes")
204665b0dc32SEd Tanous                 {
204765b0dc32SEd Tanous                     for (const auto& property : interface.second)
204865b0dc32SEd Tanous                     {
204965b0dc32SEd Tanous                         if (property.first == "UserEnabled")
205065b0dc32SEd Tanous                         {
205165b0dc32SEd Tanous                             const bool* userEnabled =
2052abf2add6SEd Tanous                                 std::get_if<bool>(&property.second);
205365b0dc32SEd Tanous                             if (userEnabled == nullptr)
205465b0dc32SEd Tanous                             {
205562598e31SEd Tanous                                 BMCWEB_LOG_ERROR("UserEnabled wasn't a bool");
205684e12cb7SAppaRao Puli                                 messages::internalError(asyncResp->res);
205784e12cb7SAppaRao Puli                                 return;
205865b0dc32SEd Tanous                             }
2059002d39b4SEd Tanous                             asyncResp->res.jsonValue["Enabled"] = *userEnabled;
206065b0dc32SEd Tanous                         }
2061002d39b4SEd Tanous                         else if (property.first == "UserLockedForFailedAttempt")
206265b0dc32SEd Tanous                         {
206365b0dc32SEd Tanous                             const bool* userLocked =
2064abf2add6SEd Tanous                                 std::get_if<bool>(&property.second);
206565b0dc32SEd Tanous                             if (userLocked == nullptr)
206665b0dc32SEd Tanous                             {
206762598e31SEd Tanous                                 BMCWEB_LOG_ERROR("UserLockedForF"
206884e12cb7SAppaRao Puli                                                  "ailedAttempt "
206962598e31SEd Tanous                                                  "wasn't a bool");
207084e12cb7SAppaRao Puli                                 messages::internalError(asyncResp->res);
207184e12cb7SAppaRao Puli                                 return;
207265b0dc32SEd Tanous                             }
2073002d39b4SEd Tanous                             asyncResp->res.jsonValue["Locked"] = *userLocked;
207420fa6a2cSEd Tanous                             nlohmann::json::array_t allowed;
207520fa6a2cSEd Tanous                             // can only unlock accounts
207620fa6a2cSEd Tanous                             allowed.emplace_back("false");
2077002d39b4SEd Tanous                             asyncResp->res
207820fa6a2cSEd Tanous                                 .jsonValue["Locked@Redfish.AllowableValues"] =
207920fa6a2cSEd Tanous                                 std::move(allowed);
208065b0dc32SEd Tanous                         }
208184e12cb7SAppaRao Puli                         else if (property.first == "UserPrivilege")
208284e12cb7SAppaRao Puli                         {
208354fc587aSNagaraju Goruganti                             const std::string* userPrivPtr =
2084002d39b4SEd Tanous                                 std::get_if<std::string>(&property.second);
208554fc587aSNagaraju Goruganti                             if (userPrivPtr == nullptr)
208684e12cb7SAppaRao Puli                             {
208762598e31SEd Tanous                                 BMCWEB_LOG_ERROR("UserPrivilege wasn't a "
208862598e31SEd Tanous                                                  "string");
208984e12cb7SAppaRao Puli                                 messages::internalError(asyncResp->res);
209084e12cb7SAppaRao Puli                                 return;
209184e12cb7SAppaRao Puli                             }
2092bd79bce8SPatrick Williams                             std::string role =
2093bd79bce8SPatrick Williams                                 getRoleIdFromPrivilege(*userPrivPtr);
209454fc587aSNagaraju Goruganti                             if (role.empty())
209584e12cb7SAppaRao Puli                             {
209662598e31SEd Tanous                                 BMCWEB_LOG_ERROR("Invalid user role");
209784e12cb7SAppaRao Puli                                 messages::internalError(asyncResp->res);
209884e12cb7SAppaRao Puli                                 return;
209984e12cb7SAppaRao Puli                             }
210054fc587aSNagaraju Goruganti                             asyncResp->res.jsonValue["RoleId"] = role;
210184e12cb7SAppaRao Puli 
21021476687dSEd Tanous                             nlohmann::json& roleEntry =
2103002d39b4SEd Tanous                                 asyncResp->res.jsonValue["Links"]["Role"];
21043b32780dSEd Tanous                             roleEntry["@odata.id"] = boost::urls::format(
21053b32780dSEd Tanous                                 "/redfish/v1/AccountService/Roles/{}", role);
210684e12cb7SAppaRao Puli                         }
2107002d39b4SEd Tanous                         else if (property.first == "UserPasswordExpired")
21083bf4e632SJoseph Reynolds                         {
21093bf4e632SJoseph Reynolds                             const bool* userPasswordExpired =
21103bf4e632SJoseph Reynolds                                 std::get_if<bool>(&property.second);
21113bf4e632SJoseph Reynolds                             if (userPasswordExpired == nullptr)
21123bf4e632SJoseph Reynolds                             {
211362598e31SEd Tanous                                 BMCWEB_LOG_ERROR(
211462598e31SEd Tanous                                     "UserPasswordExpired wasn't a bool");
21153bf4e632SJoseph Reynolds                                 messages::internalError(asyncResp->res);
21163bf4e632SJoseph Reynolds                                 return;
21173bf4e632SJoseph Reynolds                             }
2118002d39b4SEd Tanous                             asyncResp->res.jsonValue["PasswordChangeRequired"] =
21193bf4e632SJoseph Reynolds                                 *userPasswordExpired;
21203bf4e632SJoseph Reynolds                         }
2121c7229815SAbhishek Patel                         else if (property.first == "UserGroups")
2122c7229815SAbhishek Patel                         {
2123c7229815SAbhishek Patel                             const std::vector<std::string>* userGroups =
2124c7229815SAbhishek Patel                                 std::get_if<std::vector<std::string>>(
2125c7229815SAbhishek Patel                                     &property.second);
2126c7229815SAbhishek Patel                             if (userGroups == nullptr)
2127c7229815SAbhishek Patel                             {
212862598e31SEd Tanous                                 BMCWEB_LOG_ERROR(
212962598e31SEd Tanous                                     "userGroups wasn't a string vector");
2130c7229815SAbhishek Patel                                 messages::internalError(asyncResp->res);
2131c7229815SAbhishek Patel                                 return;
2132c7229815SAbhishek Patel                             }
2133bd79bce8SPatrick Williams                             if (!translateUserGroup(*userGroups,
2134bd79bce8SPatrick Williams                                                     asyncResp->res))
2135c7229815SAbhishek Patel                             {
213662598e31SEd Tanous                                 BMCWEB_LOG_ERROR("userGroups mapping failed");
2137c7229815SAbhishek Patel                                 messages::internalError(asyncResp->res);
2138c7229815SAbhishek Patel                                 return;
2139c7229815SAbhishek Patel                             }
2140c7229815SAbhishek Patel                         }
214165b0dc32SEd Tanous                     }
214265b0dc32SEd Tanous                 }
214365b0dc32SEd Tanous             }
214465b0dc32SEd Tanous 
21453b32780dSEd Tanous             asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
21463b32780dSEd Tanous                 "/redfish/v1/AccountService/Accounts/{}", accountName);
2147b9b2e0b2SEd Tanous             asyncResp->res.jsonValue["Id"] = accountName;
2148b9b2e0b2SEd Tanous             asyncResp->res.jsonValue["UserName"] = accountName;
21495eb468daSGeorge Liu         });
21501ef4c342SEd Tanous }
2151a840879dSEd Tanous 
21521ef4c342SEd Tanous inline void
215320fc307fSGunnar Mills     handleAccountDelete(App& app, const crow::Request& req,
21546c51eab1SEd Tanous                         const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
21551ef4c342SEd Tanous                         const std::string& username)
21561ef4c342SEd Tanous {
21573ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
215845ca1b86SEd Tanous     {
215945ca1b86SEd Tanous         return;
216045ca1b86SEd Tanous     }
21611ef4c342SEd Tanous 
216225b54dbaSEd Tanous     if constexpr (BMCWEB_INSECURE_DISABLE_AUTH)
216325b54dbaSEd Tanous     {
2164031514fbSJunLin Chen         // If authentication is disabled, there are no user accounts
2165d8a5d5d8SJiaqing Zhao         messages::resourceNotFound(asyncResp->res, "ManagerAccount", username);
2166031514fbSJunLin Chen         return;
216725b54dbaSEd Tanous     }
21681ef4c342SEd Tanous     sdbusplus::message::object_path tempObjPath(rootUserDbusPath);
21691ef4c342SEd Tanous     tempObjPath /= username;
21701ef4c342SEd Tanous     const std::string userPath(tempObjPath);
21711ef4c342SEd Tanous 
21721ef4c342SEd Tanous     crow::connections::systemBus->async_method_call(
21735e7e2dc5SEd Tanous         [asyncResp, username](const boost::system::error_code& ec) {
21741ef4c342SEd Tanous             if (ec)
21751ef4c342SEd Tanous             {
2176d8a5d5d8SJiaqing Zhao                 messages::resourceNotFound(asyncResp->res, "ManagerAccount",
21771ef4c342SEd Tanous                                            username);
21781ef4c342SEd Tanous                 return;
21791ef4c342SEd Tanous             }
21801ef4c342SEd Tanous 
21811ef4c342SEd Tanous             messages::accountRemoved(asyncResp->res);
21821ef4c342SEd Tanous         },
21831ef4c342SEd Tanous         "xyz.openbmc_project.User.Manager", userPath,
21841ef4c342SEd Tanous         "xyz.openbmc_project.Object.Delete", "Delete");
21851ef4c342SEd Tanous }
21861ef4c342SEd Tanous 
21871ef4c342SEd Tanous inline void
21881ef4c342SEd Tanous     handleAccountPatch(App& app, const crow::Request& req,
21891ef4c342SEd Tanous                        const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
21901ef4c342SEd Tanous                        const std::string& username)
21911ef4c342SEd Tanous {
21921ef4c342SEd Tanous     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
21931ef4c342SEd Tanous     {
21941ef4c342SEd Tanous         return;
21951ef4c342SEd Tanous     }
219625b54dbaSEd Tanous     if constexpr (BMCWEB_INSECURE_DISABLE_AUTH)
219725b54dbaSEd Tanous     {
21981ef4c342SEd Tanous         // If authentication is disabled, there are no user accounts
2199d8a5d5d8SJiaqing Zhao         messages::resourceNotFound(asyncResp->res, "ManagerAccount", username);
22001ef4c342SEd Tanous         return;
220125b54dbaSEd Tanous     }
2202a24526dcSEd Tanous     std::optional<std::string> newUserName;
2203a24526dcSEd Tanous     std::optional<std::string> password;
2204a24526dcSEd Tanous     std::optional<bool> enabled;
2205a24526dcSEd Tanous     std::optional<std::string> roleId;
220624c8542dSRatan Gupta     std::optional<bool> locked;
220758345856SAbhishek Patel     std::optional<std::vector<std::string>> accountTypes;
220858345856SAbhishek Patel 
2209031514fbSJunLin Chen     if (req.session == nullptr)
2210031514fbSJunLin Chen     {
2211031514fbSJunLin Chen         messages::internalError(asyncResp->res);
2212031514fbSJunLin Chen         return;
2213031514fbSJunLin Chen     }
2214031514fbSJunLin Chen 
22152b9c1dfeSEd Tanous     bool userSelf = (username == req.session->username);
22162b9c1dfeSEd Tanous 
2217e9cc5172SEd Tanous     Privileges effectiveUserPrivileges =
22183e72c202SNinad Palsule         redfish::getUserPrivileges(*req.session);
2219e9cc5172SEd Tanous     Privileges configureUsers = {"ConfigureUsers"};
2220e9cc5172SEd Tanous     bool userHasConfigureUsers =
2221e9cc5172SEd Tanous         effectiveUserPrivileges.isSupersetOf(configureUsers);
2222e9cc5172SEd Tanous     if (userHasConfigureUsers)
2223e9cc5172SEd Tanous     {
2224e9cc5172SEd Tanous         // Users with ConfigureUsers can modify for all users
2225*afc474aeSMyung Bae         if (!json_util::readJsonPatch( //
2226*afc474aeSMyung Bae                 req, asyncResp->res, //
2227*afc474aeSMyung Bae                 "AccountTypes", accountTypes, //
2228*afc474aeSMyung Bae                 "Enabled", enabled, //
2229*afc474aeSMyung Bae                 "Locked", locked, //
2230*afc474aeSMyung Bae                 "Password", password, //
2231*afc474aeSMyung Bae                 "RoleId", roleId, //
2232*afc474aeSMyung Bae                 "UserName", newUserName //
2233*afc474aeSMyung Bae                 ))
2234a840879dSEd Tanous         {
2235a840879dSEd Tanous             return;
2236a840879dSEd Tanous         }
2237e9cc5172SEd Tanous     }
2238e9cc5172SEd Tanous     else
2239900f9497SJoseph Reynolds     {
2240e9cc5172SEd Tanous         // ConfigureSelf accounts can only modify their own account
224158345856SAbhishek Patel         if (!userSelf)
2242900f9497SJoseph Reynolds         {
2243900f9497SJoseph Reynolds             messages::insufficientPrivilege(asyncResp->res);
2244900f9497SJoseph Reynolds             return;
2245900f9497SJoseph Reynolds         }
2246031514fbSJunLin Chen 
2247e9cc5172SEd Tanous         // ConfigureSelf accounts can only modify their password
22481ef4c342SEd Tanous         if (!json_util::readJsonPatch(req, asyncResp->res, "Password",
22491ef4c342SEd Tanous                                       password))
2250e9cc5172SEd Tanous         {
2251e9cc5172SEd Tanous             return;
2252e9cc5172SEd Tanous         }
2253900f9497SJoseph Reynolds     }
2254900f9497SJoseph Reynolds 
225566b5ca76Sjayaprakash Mutyala     // if user name is not provided in the patch method or if it
22566c51eab1SEd Tanous     // matches the user name in the URI, then we are treating it as
22576c51eab1SEd Tanous     // updating user properties other then username. If username
22586c51eab1SEd Tanous     // provided doesn't match the URI, then we are treating this as
22596c51eab1SEd Tanous     // user rename request.
226066b5ca76Sjayaprakash Mutyala     if (!newUserName || (newUserName.value() == username))
2261a840879dSEd Tanous     {
22621ef4c342SEd Tanous         updateUserProperties(asyncResp, username, password, enabled, roleId,
2263e518ef32SRavi Teja                              locked, accountTypes, userSelf, req.session);
226484e12cb7SAppaRao Puli         return;
226584e12cb7SAppaRao Puli     }
226684e12cb7SAppaRao Puli     crow::connections::systemBus->async_method_call(
22676c51eab1SEd Tanous         [asyncResp, username, password(std::move(password)),
22681ef4c342SEd Tanous          roleId(std::move(roleId)), enabled, newUser{std::string(*newUserName)},
2269e518ef32SRavi Teja          locked, userSelf, req, accountTypes(std::move(accountTypes))](
2270e81de512SEd Tanous             const boost::system::error_code& ec, sdbusplus::message_t& m) {
227184e12cb7SAppaRao Puli             if (ec)
227284e12cb7SAppaRao Puli             {
2273002d39b4SEd Tanous                 userErrorMessageHandler(m.get_error(), asyncResp, newUser,
2274002d39b4SEd Tanous                                         username);
2275a840879dSEd Tanous                 return;
2276a840879dSEd Tanous             }
2277a840879dSEd Tanous 
2278002d39b4SEd Tanous             updateUserProperties(asyncResp, newUser, password, enabled, roleId,
2279e518ef32SRavi Teja                                  locked, accountTypes, userSelf, req.session);
228084e12cb7SAppaRao Puli         },
22811ef4c342SEd Tanous         "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
228284e12cb7SAppaRao Puli         "xyz.openbmc_project.User.Manager", "RenameUser", username,
228384e12cb7SAppaRao Puli         *newUserName);
22841ef4c342SEd Tanous }
22851ef4c342SEd Tanous 
22861ef4c342SEd Tanous inline void requestAccountServiceRoutes(App& app)
22871ef4c342SEd Tanous {
22881ef4c342SEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/AccountService/")
22894c7d4d33SEd Tanous         .privileges(redfish::privileges::headAccountService)
22904c7d4d33SEd Tanous         .methods(boost::beast::http::verb::head)(
22914c7d4d33SEd Tanous             std::bind_front(handleAccountServiceHead, std::ref(app)));
22924c7d4d33SEd Tanous 
22934c7d4d33SEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/AccountService/")
22941ef4c342SEd Tanous         .privileges(redfish::privileges::getAccountService)
22951ef4c342SEd Tanous         .methods(boost::beast::http::verb::get)(
22961ef4c342SEd Tanous             std::bind_front(handleAccountServiceGet, std::ref(app)));
22971ef4c342SEd Tanous 
22981ef4c342SEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/AccountService/")
22991ef4c342SEd Tanous         .privileges(redfish::privileges::patchAccountService)
23001ef4c342SEd Tanous         .methods(boost::beast::http::verb::patch)(
23011ef4c342SEd Tanous             std::bind_front(handleAccountServicePatch, std::ref(app)));
23021ef4c342SEd Tanous 
23031aa375b8SEd Tanous     BMCWEB_ROUTE(
23041aa375b8SEd Tanous         app,
2305e9f12014SEd Tanous         "/redfish/v1/AccountService/MultiFactorAuth/ClientCertificate/Certificates/")
23061aa375b8SEd Tanous         .privileges(redfish::privileges::headCertificateCollection)
23071aa375b8SEd Tanous         .methods(boost::beast::http::verb::head)(std::bind_front(
23081aa375b8SEd Tanous             handleAccountServiceClientCertificatesHead, std::ref(app)));
23091aa375b8SEd Tanous 
23101aa375b8SEd Tanous     BMCWEB_ROUTE(
23111aa375b8SEd Tanous         app,
2312e9f12014SEd Tanous         "/redfish/v1/AccountService/MultiFactorAuth/ClientCertificate/Certificates/")
23131aa375b8SEd Tanous         .privileges(redfish::privileges::getCertificateCollection)
23141aa375b8SEd Tanous         .methods(boost::beast::http::verb::get)(std::bind_front(
23151aa375b8SEd Tanous             handleAccountServiceClientCertificatesGet, std::ref(app)));
23161aa375b8SEd Tanous 
23171aa375b8SEd Tanous     BMCWEB_ROUTE(
23181aa375b8SEd Tanous         app,
2319e9f12014SEd Tanous         "/redfish/v1/AccountService/MultiFactorAuth/ClientCertificate/Certificates/<str>/")
23201aa375b8SEd Tanous         .privileges(redfish::privileges::headCertificate)
23211aa375b8SEd Tanous         .methods(boost::beast::http::verb::head)(std::bind_front(
23221aa375b8SEd Tanous             handleAccountServiceClientCertificatesInstanceHead, std::ref(app)));
23231aa375b8SEd Tanous 
23241aa375b8SEd Tanous     BMCWEB_ROUTE(
23251aa375b8SEd Tanous         app,
23261aa375b8SEd Tanous         "/redfish/v1/AccountService/MultiFactorAuth/ClientCertificate/Certificates/<str>/")
23271aa375b8SEd Tanous         .privileges(redfish::privileges::getCertificate)
23281aa375b8SEd Tanous         .methods(boost::beast::http::verb::get)(std::bind_front(
23291aa375b8SEd Tanous             handleAccountServiceClientCertificatesInstanceGet, std::ref(app)));
23301aa375b8SEd Tanous 
23311ef4c342SEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/")
23324c7d4d33SEd Tanous         .privileges(redfish::privileges::headManagerAccountCollection)
23334c7d4d33SEd Tanous         .methods(boost::beast::http::verb::head)(
23344c7d4d33SEd Tanous             std::bind_front(handleAccountCollectionHead, std::ref(app)));
23354c7d4d33SEd Tanous 
23364c7d4d33SEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/")
23371ef4c342SEd Tanous         .privileges(redfish::privileges::getManagerAccountCollection)
23381ef4c342SEd Tanous         .methods(boost::beast::http::verb::get)(
23391ef4c342SEd Tanous             std::bind_front(handleAccountCollectionGet, std::ref(app)));
23401ef4c342SEd Tanous 
23411ef4c342SEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/")
23421ef4c342SEd Tanous         .privileges(redfish::privileges::postManagerAccountCollection)
23431ef4c342SEd Tanous         .methods(boost::beast::http::verb::post)(
23441ef4c342SEd Tanous             std::bind_front(handleAccountCollectionPost, std::ref(app)));
23451ef4c342SEd Tanous 
23461ef4c342SEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/<str>/")
23474c7d4d33SEd Tanous         .privileges(redfish::privileges::headManagerAccount)
23484c7d4d33SEd Tanous         .methods(boost::beast::http::verb::head)(
23494c7d4d33SEd Tanous             std::bind_front(handleAccountHead, std::ref(app)));
23504c7d4d33SEd Tanous 
23514c7d4d33SEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/<str>/")
23521ef4c342SEd Tanous         .privileges(redfish::privileges::getManagerAccount)
23531ef4c342SEd Tanous         .methods(boost::beast::http::verb::get)(
23541ef4c342SEd Tanous             std::bind_front(handleAccountGet, std::ref(app)));
23551ef4c342SEd Tanous 
23561ef4c342SEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/<str>/")
23571ef4c342SEd Tanous         // TODO this privilege should be using the generated endpoints, but
23581ef4c342SEd Tanous         // because of the special handling of ConfigureSelf, it's not able to
23591ef4c342SEd Tanous         // yet
23601ef4c342SEd Tanous         .privileges({{"ConfigureUsers"}, {"ConfigureSelf"}})
23611ef4c342SEd Tanous         .methods(boost::beast::http::verb::patch)(
23621ef4c342SEd Tanous             std::bind_front(handleAccountPatch, std::ref(app)));
236384e12cb7SAppaRao Puli 
23646c51eab1SEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/<str>/")
2365ed398213SEd Tanous         .privileges(redfish::privileges::deleteManagerAccount)
23666c51eab1SEd Tanous         .methods(boost::beast::http::verb::delete_)(
236720fc307fSGunnar Mills             std::bind_front(handleAccountDelete, std::ref(app)));
236806e086d9SEd Tanous }
236988d16c9aSLewanczyk, Dawid 
237088d16c9aSLewanczyk, Dawid } // namespace redfish
2371