xref: /openbmc/bmcweb/features/redfish/lib/account_service.hpp (revision 6973a5828894d8c4ff04650f9b40ce6b376a5226)
188d16c9aSLewanczyk, Dawid /*
288d16c9aSLewanczyk, Dawid // Copyright (c) 2018 Intel Corporation
388d16c9aSLewanczyk, Dawid //
488d16c9aSLewanczyk, Dawid // Licensed under the Apache License, Version 2.0 (the "License");
588d16c9aSLewanczyk, Dawid // you may not use this file except in compliance with the License.
688d16c9aSLewanczyk, Dawid // You may obtain a copy of the License at
788d16c9aSLewanczyk, Dawid //
888d16c9aSLewanczyk, Dawid //      http://www.apache.org/licenses/LICENSE-2.0
988d16c9aSLewanczyk, Dawid //
1088d16c9aSLewanczyk, Dawid // Unless required by applicable law or agreed to in writing, software
1188d16c9aSLewanczyk, Dawid // distributed under the License is distributed on an "AS IS" BASIS,
1288d16c9aSLewanczyk, Dawid // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1388d16c9aSLewanczyk, Dawid // See the License for the specific language governing permissions and
1488d16c9aSLewanczyk, Dawid // limitations under the License.
1588d16c9aSLewanczyk, Dawid */
1688d16c9aSLewanczyk, Dawid #pragma once
1788d16c9aSLewanczyk, Dawid #include "node.hpp"
1888d16c9aSLewanczyk, Dawid 
1924c8542dSRatan Gupta #include <dbus_utility.hpp>
2065b0dc32SEd Tanous #include <error_messages.hpp>
21b9b2e0b2SEd Tanous #include <openbmc_dbus_rest.hpp>
22a840879dSEd Tanous #include <utils/json_utils.hpp>
23abf2add6SEd Tanous #include <variant>
24b9b2e0b2SEd Tanous 
251abe55efSEd Tanous namespace redfish
261abe55efSEd Tanous {
2788d16c9aSLewanczyk, Dawid 
28*6973a582SRatan Gupta constexpr const char* ldapConfigObject =
29*6973a582SRatan Gupta     "/xyz/openbmc_project/user/ldap/openldap";
30*6973a582SRatan Gupta constexpr const char* ldapRootObject = "/xyz/openbmc_project/user/ldap";
31*6973a582SRatan Gupta constexpr const char* ldapDbusService = "xyz.openbmc_project.Ldap.Config";
32*6973a582SRatan Gupta constexpr const char* ldapConfigInterface =
33*6973a582SRatan Gupta     "xyz.openbmc_project.User.Ldap.Config";
34*6973a582SRatan Gupta constexpr const char* ldapCreateInterface =
35*6973a582SRatan Gupta     "xyz.openbmc_project.User.Ldap.Create";
36*6973a582SRatan Gupta constexpr const char* ldapEnableInterface = "xyz.openbmc_project.Object.Enable";
37*6973a582SRatan Gupta constexpr const char* dbusObjManagerIntf = "org.freedesktop.DBus.ObjectManager";
38*6973a582SRatan Gupta constexpr const char* propertyInterface = "org.freedesktop.DBus.Properties";
39*6973a582SRatan Gupta constexpr const char* mapperBusName = "xyz.openbmc_project.ObjectMapper";
40*6973a582SRatan Gupta constexpr const char* mapperObjectPath = "/xyz/openbmc_project/object_mapper";
41*6973a582SRatan Gupta constexpr const char* mapperIntf = "xyz.openbmc_project.ObjectMapper";
42*6973a582SRatan Gupta 
43*6973a582SRatan Gupta struct LDAPConfigData
44*6973a582SRatan Gupta {
45*6973a582SRatan Gupta     std::string uri{};
46*6973a582SRatan Gupta     std::string bindDN{};
47*6973a582SRatan Gupta     std::string baseDN{};
48*6973a582SRatan Gupta     std::string searchScope{};
49*6973a582SRatan Gupta     std::string serverType{};
50*6973a582SRatan Gupta     bool serviceEnabled = false;
51*6973a582SRatan Gupta     std::string userNameAttribute{};
52*6973a582SRatan Gupta     std::string groupAttribute{};
53*6973a582SRatan Gupta };
54*6973a582SRatan Gupta 
55b9b2e0b2SEd Tanous using ManagedObjectType = std::vector<std::pair<
56b9b2e0b2SEd Tanous     sdbusplus::message::object_path,
57b9b2e0b2SEd Tanous     boost::container::flat_map<
58abf2add6SEd Tanous         std::string, boost::container::flat_map<
59abf2add6SEd Tanous                          std::string, std::variant<bool, std::string>>>>>;
60*6973a582SRatan Gupta using GetObjectType =
61*6973a582SRatan Gupta     std::vector<std::pair<std::string, std::vector<std::string>>>;
6284e12cb7SAppaRao Puli 
63ae29b8c4SAdriana Kobylak inline std::string getPrivilegeFromRoleId(std::string_view role)
6484e12cb7SAppaRao Puli {
6584e12cb7SAppaRao Puli     if (role == "priv-admin")
6684e12cb7SAppaRao Puli     {
6784e12cb7SAppaRao Puli         return "Administrator";
6884e12cb7SAppaRao Puli     }
6984e12cb7SAppaRao Puli     else if (role == "priv-callback")
7084e12cb7SAppaRao Puli     {
7184e12cb7SAppaRao Puli         return "Callback";
7284e12cb7SAppaRao Puli     }
7384e12cb7SAppaRao Puli     else if (role == "priv-user")
7484e12cb7SAppaRao Puli     {
7584e12cb7SAppaRao Puli         return "User";
7684e12cb7SAppaRao Puli     }
7784e12cb7SAppaRao Puli     else if (role == "priv-operator")
7884e12cb7SAppaRao Puli     {
7984e12cb7SAppaRao Puli         return "Operator";
8084e12cb7SAppaRao Puli     }
8184e12cb7SAppaRao Puli     return "";
8284e12cb7SAppaRao Puli }
83ae29b8c4SAdriana Kobylak inline std::string getRoleIdFromPrivilege(std::string_view role)
8484e12cb7SAppaRao Puli {
8584e12cb7SAppaRao Puli     if (role == "Administrator")
8684e12cb7SAppaRao Puli     {
8784e12cb7SAppaRao Puli         return "priv-admin";
8884e12cb7SAppaRao Puli     }
8984e12cb7SAppaRao Puli     else if (role == "Callback")
9084e12cb7SAppaRao Puli     {
9184e12cb7SAppaRao Puli         return "priv-callback";
9284e12cb7SAppaRao Puli     }
9384e12cb7SAppaRao Puli     else if (role == "User")
9484e12cb7SAppaRao Puli     {
9584e12cb7SAppaRao Puli         return "priv-user";
9684e12cb7SAppaRao Puli     }
9784e12cb7SAppaRao Puli     else if (role == "Operator")
9884e12cb7SAppaRao Puli     {
9984e12cb7SAppaRao Puli         return "priv-operator";
10084e12cb7SAppaRao Puli     }
10184e12cb7SAppaRao Puli     return "";
10284e12cb7SAppaRao Puli }
103b9b2e0b2SEd Tanous 
104*6973a582SRatan Gupta void parseLDAPConfigData(nlohmann::json& json_response,
105*6973a582SRatan Gupta                          const LDAPConfigData& confData)
106*6973a582SRatan Gupta {
107*6973a582SRatan Gupta     std::string service = "LDAPService";
108*6973a582SRatan Gupta     json_response["LDAP"] = {
109*6973a582SRatan Gupta         {"AccountProviderType", service},
110*6973a582SRatan Gupta         {"AccountProviderType@Redfish.AllowableValues",
111*6973a582SRatan Gupta          nlohmann::json::array({service})},
112*6973a582SRatan Gupta         {"ServiceEnabled", confData.serviceEnabled},
113*6973a582SRatan Gupta         {"ServiceAddresses", nlohmann::json::array({confData.uri})},
114*6973a582SRatan Gupta         {"Authentication",
115*6973a582SRatan Gupta          {{"AuthenticationType", "UsernameAndPassword"},
116*6973a582SRatan Gupta           {"AuthenticationType@Redfish.AllowableValues",
117*6973a582SRatan Gupta            nlohmann::json::array({"UsernameAndPassword"})},
118*6973a582SRatan Gupta           {"Username", confData.bindDN},
119*6973a582SRatan Gupta           {"Password", nullptr}}},
120*6973a582SRatan Gupta         {"LDAPService",
121*6973a582SRatan Gupta          {{"SearchSettings",
122*6973a582SRatan Gupta            {{"BaseDistinguishedNames",
123*6973a582SRatan Gupta              nlohmann::json::array({confData.baseDN})},
124*6973a582SRatan Gupta             {"UsernameAttribute", confData.userNameAttribute},
125*6973a582SRatan Gupta             {"GroupsAttribute", confData.groupAttribute}}}}},
126*6973a582SRatan Gupta     };
127*6973a582SRatan Gupta }
128*6973a582SRatan Gupta 
129*6973a582SRatan Gupta /**
130*6973a582SRatan Gupta  * Function that retrieves all properties for LDAP config object
131*6973a582SRatan Gupta  * into JSON
132*6973a582SRatan Gupta  */
133*6973a582SRatan Gupta template <typename CallbackFunc>
134*6973a582SRatan Gupta inline void getLDAPConfigData(const std::string& ldapType,
135*6973a582SRatan Gupta                               CallbackFunc&& callback)
136*6973a582SRatan Gupta {
137*6973a582SRatan Gupta     auto getConfig = [callback,
138*6973a582SRatan Gupta                       ldapType](const boost::system::error_code error_code,
139*6973a582SRatan Gupta                                 const ManagedObjectType& ldapObjects) {
140*6973a582SRatan Gupta         LDAPConfigData confData{};
141*6973a582SRatan Gupta         if (error_code)
142*6973a582SRatan Gupta         {
143*6973a582SRatan Gupta             callback(false, confData);
144*6973a582SRatan Gupta             BMCWEB_LOG_ERROR << "D-Bus responses error: " << error_code;
145*6973a582SRatan Gupta             return;
146*6973a582SRatan Gupta         }
147*6973a582SRatan Gupta         std::string ldapConfigObjectStr = std::string(ldapConfigObject);
148*6973a582SRatan Gupta         std::string ldapEnableInterfaceStr = std::string(ldapEnableInterface);
149*6973a582SRatan Gupta         std::string ldapConfigInterfaceStr = std::string(ldapConfigInterface);
150*6973a582SRatan Gupta         for (const auto& object : ldapObjects)
151*6973a582SRatan Gupta         {
152*6973a582SRatan Gupta             if (object.first == ldapConfigObjectStr)
153*6973a582SRatan Gupta             {
154*6973a582SRatan Gupta                 for (const auto& interface : object.second)
155*6973a582SRatan Gupta                 {
156*6973a582SRatan Gupta                     if (interface.first == ldapEnableInterfaceStr)
157*6973a582SRatan Gupta                     {
158*6973a582SRatan Gupta                         // rest of the properties are string.
159*6973a582SRatan Gupta                         for (const auto& property : interface.second)
160*6973a582SRatan Gupta                         {
161*6973a582SRatan Gupta                             if (property.first == "Enabled")
162*6973a582SRatan Gupta                             {
163*6973a582SRatan Gupta                                 const bool* value =
164*6973a582SRatan Gupta                                     std::get_if<bool>(&property.second);
165*6973a582SRatan Gupta                                 if (value == nullptr)
166*6973a582SRatan Gupta                                 {
167*6973a582SRatan Gupta                                     continue;
168*6973a582SRatan Gupta                                 }
169*6973a582SRatan Gupta                                 confData.serviceEnabled = *value;
170*6973a582SRatan Gupta                                 break;
171*6973a582SRatan Gupta                             }
172*6973a582SRatan Gupta                         }
173*6973a582SRatan Gupta                     }
174*6973a582SRatan Gupta                     else if (interface.first == ldapConfigInterfaceStr)
175*6973a582SRatan Gupta                     {
176*6973a582SRatan Gupta 
177*6973a582SRatan Gupta                         for (const auto& property : interface.second)
178*6973a582SRatan Gupta                         {
179*6973a582SRatan Gupta                             const std::string* value =
180*6973a582SRatan Gupta                                 std::get_if<std::string>(&property.second);
181*6973a582SRatan Gupta                             if (value == nullptr)
182*6973a582SRatan Gupta                             {
183*6973a582SRatan Gupta                                 continue;
184*6973a582SRatan Gupta                             }
185*6973a582SRatan Gupta                             if (property.first == "LDAPServerURI")
186*6973a582SRatan Gupta                             {
187*6973a582SRatan Gupta                                 confData.uri = *value;
188*6973a582SRatan Gupta                             }
189*6973a582SRatan Gupta                             else if (property.first == "LDAPBindDN")
190*6973a582SRatan Gupta                             {
191*6973a582SRatan Gupta                                 confData.bindDN = *value;
192*6973a582SRatan Gupta                             }
193*6973a582SRatan Gupta                             else if (property.first == "LDAPBaseDN")
194*6973a582SRatan Gupta                             {
195*6973a582SRatan Gupta                                 confData.baseDN = *value;
196*6973a582SRatan Gupta                             }
197*6973a582SRatan Gupta                             else if (property.first == "LDAPSearchScope")
198*6973a582SRatan Gupta                             {
199*6973a582SRatan Gupta                                 confData.searchScope = *value;
200*6973a582SRatan Gupta                             }
201*6973a582SRatan Gupta                             else if (property.first == "LDAPType")
202*6973a582SRatan Gupta                             {
203*6973a582SRatan Gupta                                 confData.serverType = *value;
204*6973a582SRatan Gupta                             }
205*6973a582SRatan Gupta                             else if (property.first == "GroupNameAttribute")
206*6973a582SRatan Gupta                             {
207*6973a582SRatan Gupta                                 confData.groupAttribute = *value;
208*6973a582SRatan Gupta                             }
209*6973a582SRatan Gupta                             else if (property.first == "UserNameAttribute")
210*6973a582SRatan Gupta                             {
211*6973a582SRatan Gupta                                 confData.userNameAttribute = *value;
212*6973a582SRatan Gupta                             }
213*6973a582SRatan Gupta                         }
214*6973a582SRatan Gupta                     }
215*6973a582SRatan Gupta                 }
216*6973a582SRatan Gupta 
217*6973a582SRatan Gupta                 callback(true, confData);
218*6973a582SRatan Gupta                 break;
219*6973a582SRatan Gupta             }
220*6973a582SRatan Gupta         }
221*6973a582SRatan Gupta     };
222*6973a582SRatan Gupta     auto getServiceName = [callback, getConfig(std::move(getConfig))](
223*6973a582SRatan Gupta                               const boost::system::error_code ec,
224*6973a582SRatan Gupta                               const GetObjectType& resp) {
225*6973a582SRatan Gupta         LDAPConfigData confData{};
226*6973a582SRatan Gupta         if (ec || resp.empty())
227*6973a582SRatan Gupta         {
228*6973a582SRatan Gupta             BMCWEB_LOG_ERROR
229*6973a582SRatan Gupta                 << "DBUS response error during getting of service name: " << ec;
230*6973a582SRatan Gupta             callback(false, confData);
231*6973a582SRatan Gupta             return;
232*6973a582SRatan Gupta         }
233*6973a582SRatan Gupta         std::string service = resp.begin()->first;
234*6973a582SRatan Gupta         crow::connections::systemBus->async_method_call(
235*6973a582SRatan Gupta             std::move(getConfig), service, ldapRootObject, dbusObjManagerIntf,
236*6973a582SRatan Gupta             "GetManagedObjects");
237*6973a582SRatan Gupta     };
238*6973a582SRatan Gupta 
239*6973a582SRatan Gupta     const std::array<std::string, 2> interfaces = {ldapEnableInterface,
240*6973a582SRatan Gupta                                                    ldapConfigInterface};
241*6973a582SRatan Gupta 
242*6973a582SRatan Gupta     crow::connections::systemBus->async_method_call(
243*6973a582SRatan Gupta         std::move(getServiceName), mapperBusName, mapperObjectPath, mapperIntf,
244*6973a582SRatan Gupta         "GetObject", ldapConfigObject, interfaces);
245*6973a582SRatan Gupta }
246*6973a582SRatan Gupta 
2471abe55efSEd Tanous class AccountService : public Node
2481abe55efSEd Tanous {
24988d16c9aSLewanczyk, Dawid   public:
2501abe55efSEd Tanous     AccountService(CrowApp& app) : Node(app, "/redfish/v1/AccountService/")
2511abe55efSEd Tanous     {
2523ebd75f7SEd Tanous         entityPrivileges = {
2534b1b8683SBorawski.Lukasz             {boost::beast::http::verb::get,
2544b1b8683SBorawski.Lukasz              {{"ConfigureUsers"}, {"ConfigureManager"}}},
255e0d918bcSEd Tanous             {boost::beast::http::verb::head, {{"Login"}}},
256e0d918bcSEd Tanous             {boost::beast::http::verb::patch, {{"ConfigureUsers"}}},
257e0d918bcSEd Tanous             {boost::beast::http::verb::put, {{"ConfigureUsers"}}},
258e0d918bcSEd Tanous             {boost::beast::http::verb::delete_, {{"ConfigureUsers"}}},
259e0d918bcSEd Tanous             {boost::beast::http::verb::post, {{"ConfigureUsers"}}}};
26088d16c9aSLewanczyk, Dawid     }
26188d16c9aSLewanczyk, Dawid 
26288d16c9aSLewanczyk, Dawid   private:
26355c7b7a2SEd Tanous     void doGet(crow::Response& res, const crow::Request& req,
2641abe55efSEd Tanous                const std::vector<std::string>& params) override
2651abe55efSEd Tanous     {
2663d958bbcSAppaRao Puli         auto asyncResp = std::make_shared<AsyncResp>(res);
2673d958bbcSAppaRao Puli         res.jsonValue = {
2683d958bbcSAppaRao Puli             {"@odata.context", "/redfish/v1/"
2693d958bbcSAppaRao Puli                                "$metadata#AccountService.AccountService"},
2703d958bbcSAppaRao Puli             {"@odata.id", "/redfish/v1/AccountService"},
2713d958bbcSAppaRao Puli             {"@odata.type", "#AccountService."
272*6973a582SRatan Gupta                             "v1_3_1.AccountService"},
2733d958bbcSAppaRao Puli             {"Id", "AccountService"},
2743d958bbcSAppaRao Puli             {"Name", "Account Service"},
2753d958bbcSAppaRao Puli             {"Description", "Account Service"},
2763d958bbcSAppaRao Puli             {"ServiceEnabled", true},
277343ff2e1SAppaRao Puli             {"MaxPasswordLength", 20},
2783d958bbcSAppaRao Puli             {"Accounts",
2793d958bbcSAppaRao Puli              {{"@odata.id", "/redfish/v1/AccountService/Accounts"}}},
2803d958bbcSAppaRao Puli             {"Roles", {{"@odata.id", "/redfish/v1/AccountService/Roles"}}}};
2810f74e643SEd Tanous 
2823d958bbcSAppaRao Puli         crow::connections::systemBus->async_method_call(
2833d958bbcSAppaRao Puli             [asyncResp](
2843d958bbcSAppaRao Puli                 const boost::system::error_code ec,
2853d958bbcSAppaRao Puli                 const std::vector<std::pair<
286abf2add6SEd Tanous                     std::string, std::variant<uint32_t, uint16_t, uint8_t>>>&
2873d958bbcSAppaRao Puli                     propertiesList) {
2883d958bbcSAppaRao Puli                 if (ec)
2893d958bbcSAppaRao Puli                 {
2903d958bbcSAppaRao Puli                     messages::internalError(asyncResp->res);
2913d958bbcSAppaRao Puli                     return;
2923d958bbcSAppaRao Puli                 }
2933d958bbcSAppaRao Puli                 BMCWEB_LOG_DEBUG << "Got " << propertiesList.size()
2943d958bbcSAppaRao Puli                                  << "properties for AccountService";
2953d958bbcSAppaRao Puli                 for (const std::pair<std::string,
296abf2add6SEd Tanous                                      std::variant<uint32_t, uint16_t, uint8_t>>&
2973d958bbcSAppaRao Puli                          property : propertiesList)
2983d958bbcSAppaRao Puli                 {
2993d958bbcSAppaRao Puli                     if (property.first == "MinPasswordLength")
3003d958bbcSAppaRao Puli                     {
3013d958bbcSAppaRao Puli                         const uint8_t* value =
302abf2add6SEd Tanous                             std::get_if<uint8_t>(&property.second);
3033d958bbcSAppaRao Puli                         if (value != nullptr)
3043d958bbcSAppaRao Puli                         {
3053d958bbcSAppaRao Puli                             asyncResp->res.jsonValue["MinPasswordLength"] =
3063d958bbcSAppaRao Puli                                 *value;
3073d958bbcSAppaRao Puli                         }
3083d958bbcSAppaRao Puli                     }
3093d958bbcSAppaRao Puli                     if (property.first == "AccountUnlockTimeout")
3103d958bbcSAppaRao Puli                     {
3113d958bbcSAppaRao Puli                         const uint32_t* value =
312abf2add6SEd Tanous                             std::get_if<uint32_t>(&property.second);
3133d958bbcSAppaRao Puli                         if (value != nullptr)
3143d958bbcSAppaRao Puli                         {
3153d958bbcSAppaRao Puli                             asyncResp->res.jsonValue["AccountLockoutDuration"] =
3163d958bbcSAppaRao Puli                                 *value;
3173d958bbcSAppaRao Puli                         }
3183d958bbcSAppaRao Puli                     }
3193d958bbcSAppaRao Puli                     if (property.first == "MaxLoginAttemptBeforeLockout")
3203d958bbcSAppaRao Puli                     {
3213d958bbcSAppaRao Puli                         const uint16_t* value =
322abf2add6SEd Tanous                             std::get_if<uint16_t>(&property.second);
3233d958bbcSAppaRao Puli                         if (value != nullptr)
3243d958bbcSAppaRao Puli                         {
3253d958bbcSAppaRao Puli                             asyncResp->res
3263d958bbcSAppaRao Puli                                 .jsonValue["AccountLockoutThreshold"] = *value;
3273d958bbcSAppaRao Puli                         }
3283d958bbcSAppaRao Puli                     }
3293d958bbcSAppaRao Puli                 }
3303d958bbcSAppaRao Puli             },
3313d958bbcSAppaRao Puli             "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
3323d958bbcSAppaRao Puli             "org.freedesktop.DBus.Properties", "GetAll",
3333d958bbcSAppaRao Puli             "xyz.openbmc_project.User.AccountPolicy");
334*6973a582SRatan Gupta 
335*6973a582SRatan Gupta         std::string ldapType = "LDAP";
336*6973a582SRatan Gupta         getLDAPConfigData(
337*6973a582SRatan Gupta             ldapType,
338*6973a582SRatan Gupta             [asyncResp, ldapType](bool success, LDAPConfigData& confData) {
339*6973a582SRatan Gupta                 parseLDAPConfigData(asyncResp->res.jsonValue, confData);
340*6973a582SRatan Gupta             });
3413d958bbcSAppaRao Puli     }
342*6973a582SRatan Gupta 
3433d958bbcSAppaRao Puli     void doPatch(crow::Response& res, const crow::Request& req,
3443d958bbcSAppaRao Puli                  const std::vector<std::string>& params) override
3453d958bbcSAppaRao Puli     {
3463d958bbcSAppaRao Puli         auto asyncResp = std::make_shared<AsyncResp>(res);
3473d958bbcSAppaRao Puli 
3483d958bbcSAppaRao Puli         std::optional<uint32_t> unlockTimeout;
3493d958bbcSAppaRao Puli         std::optional<uint16_t> lockoutThreshold;
35019fb6e71SRatan Gupta         std::optional<uint16_t> minPasswordLength;
35119fb6e71SRatan Gupta         std::optional<uint16_t> maxPasswordLength;
35219fb6e71SRatan Gupta 
3533d958bbcSAppaRao Puli         if (!json_util::readJson(req, res, "AccountLockoutDuration",
3543d958bbcSAppaRao Puli                                  unlockTimeout, "AccountLockoutThreshold",
35519fb6e71SRatan Gupta                                  lockoutThreshold, "MaxPasswordLength",
35619fb6e71SRatan Gupta                                  maxPasswordLength, "MinPasswordLength",
35719fb6e71SRatan Gupta                                  minPasswordLength))
3583d958bbcSAppaRao Puli         {
3593d958bbcSAppaRao Puli             return;
3603d958bbcSAppaRao Puli         }
36119fb6e71SRatan Gupta 
36219fb6e71SRatan Gupta         if (minPasswordLength)
36319fb6e71SRatan Gupta         {
36419fb6e71SRatan Gupta             messages::propertyNotWritable(asyncResp->res, "MinPasswordLength");
36519fb6e71SRatan Gupta         }
36619fb6e71SRatan Gupta 
36719fb6e71SRatan Gupta         if (maxPasswordLength)
36819fb6e71SRatan Gupta         {
36919fb6e71SRatan Gupta             messages::propertyNotWritable(asyncResp->res, "MaxPasswordLength");
37019fb6e71SRatan Gupta         }
37119fb6e71SRatan Gupta 
3723d958bbcSAppaRao Puli         if (unlockTimeout)
3733d958bbcSAppaRao Puli         {
3743d958bbcSAppaRao Puli             crow::connections::systemBus->async_method_call(
3753d958bbcSAppaRao Puli                 [asyncResp](const boost::system::error_code ec) {
3763d958bbcSAppaRao Puli                     if (ec)
3773d958bbcSAppaRao Puli                     {
3783d958bbcSAppaRao Puli                         messages::internalError(asyncResp->res);
3793d958bbcSAppaRao Puli                         return;
3803d958bbcSAppaRao Puli                     }
381add6133bSRatan Gupta                     messages::success(asyncResp->res);
3823d958bbcSAppaRao Puli                 },
3833d958bbcSAppaRao Puli                 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
3843d958bbcSAppaRao Puli                 "org.freedesktop.DBus.Properties", "Set",
3853d958bbcSAppaRao Puli                 "xyz.openbmc_project.User.AccountPolicy",
386abf2add6SEd Tanous                 "AccountUnlockTimeout", std::variant<uint32_t>(*unlockTimeout));
3873d958bbcSAppaRao Puli         }
3883d958bbcSAppaRao Puli         if (lockoutThreshold)
3893d958bbcSAppaRao Puli         {
3903d958bbcSAppaRao Puli             crow::connections::systemBus->async_method_call(
3913d958bbcSAppaRao Puli                 [asyncResp](const boost::system::error_code ec) {
3923d958bbcSAppaRao Puli                     if (ec)
3933d958bbcSAppaRao Puli                     {
3943d958bbcSAppaRao Puli                         messages::internalError(asyncResp->res);
3953d958bbcSAppaRao Puli                         return;
3963d958bbcSAppaRao Puli                     }
397add6133bSRatan Gupta                     messages::success(asyncResp->res);
3983d958bbcSAppaRao Puli                 },
3993d958bbcSAppaRao Puli                 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
4003d958bbcSAppaRao Puli                 "org.freedesktop.DBus.Properties", "Set",
4013d958bbcSAppaRao Puli                 "xyz.openbmc_project.User.AccountPolicy",
4023d958bbcSAppaRao Puli                 "MaxLoginAttemptBeforeLockout",
403abf2add6SEd Tanous                 std::variant<uint16_t>(*lockoutThreshold));
4043d958bbcSAppaRao Puli         }
40588d16c9aSLewanczyk, Dawid     }
40688d16c9aSLewanczyk, Dawid };
407f00032dbSTanous 
408b9b2e0b2SEd Tanous class AccountsCollection : public Node
409b9b2e0b2SEd Tanous {
410b9b2e0b2SEd Tanous   public:
411b9b2e0b2SEd Tanous     AccountsCollection(CrowApp& app) :
412b9b2e0b2SEd Tanous         Node(app, "/redfish/v1/AccountService/Accounts/")
413b9b2e0b2SEd Tanous     {
414b9b2e0b2SEd Tanous         entityPrivileges = {
415b9b2e0b2SEd Tanous             {boost::beast::http::verb::get,
416b9b2e0b2SEd Tanous              {{"ConfigureUsers"}, {"ConfigureManager"}}},
417b9b2e0b2SEd Tanous             {boost::beast::http::verb::head, {{"Login"}}},
418b9b2e0b2SEd Tanous             {boost::beast::http::verb::patch, {{"ConfigureUsers"}}},
419b9b2e0b2SEd Tanous             {boost::beast::http::verb::put, {{"ConfigureUsers"}}},
420b9b2e0b2SEd Tanous             {boost::beast::http::verb::delete_, {{"ConfigureUsers"}}},
421b9b2e0b2SEd Tanous             {boost::beast::http::verb::post, {{"ConfigureUsers"}}}};
422b9b2e0b2SEd Tanous     }
423b9b2e0b2SEd Tanous 
424b9b2e0b2SEd Tanous   private:
425b9b2e0b2SEd Tanous     void doGet(crow::Response& res, const crow::Request& req,
426b9b2e0b2SEd Tanous                const std::vector<std::string>& params) override
427b9b2e0b2SEd Tanous     {
428b9b2e0b2SEd Tanous         auto asyncResp = std::make_shared<AsyncResp>(res);
4290f74e643SEd Tanous         res.jsonValue = {{"@odata.context",
4300f74e643SEd Tanous                           "/redfish/v1/"
4310f74e643SEd Tanous                           "$metadata#ManagerAccountCollection."
4320f74e643SEd Tanous                           "ManagerAccountCollection"},
4330f74e643SEd Tanous                          {"@odata.id", "/redfish/v1/AccountService/Accounts"},
4340f74e643SEd Tanous                          {"@odata.type", "#ManagerAccountCollection."
4350f74e643SEd Tanous                                          "ManagerAccountCollection"},
4360f74e643SEd Tanous                          {"Name", "Accounts Collection"},
4370f74e643SEd Tanous                          {"Description", "BMC User Accounts"}};
4380f74e643SEd Tanous 
439b9b2e0b2SEd Tanous         crow::connections::systemBus->async_method_call(
440b9b2e0b2SEd Tanous             [asyncResp](const boost::system::error_code ec,
441b9b2e0b2SEd Tanous                         const ManagedObjectType& users) {
442b9b2e0b2SEd Tanous                 if (ec)
443b9b2e0b2SEd Tanous                 {
444f12894f8SJason M. Bills                     messages::internalError(asyncResp->res);
445b9b2e0b2SEd Tanous                     return;
446b9b2e0b2SEd Tanous                 }
447b9b2e0b2SEd Tanous 
448b9b2e0b2SEd Tanous                 nlohmann::json& memberArray =
449b9b2e0b2SEd Tanous                     asyncResp->res.jsonValue["Members"];
450b9b2e0b2SEd Tanous                 memberArray = nlohmann::json::array();
451b9b2e0b2SEd Tanous 
452b9b2e0b2SEd Tanous                 asyncResp->res.jsonValue["Members@odata.count"] = users.size();
453b9b2e0b2SEd Tanous                 for (auto& user : users)
454b9b2e0b2SEd Tanous                 {
455b9b2e0b2SEd Tanous                     const std::string& path =
456b9b2e0b2SEd Tanous                         static_cast<const std::string&>(user.first);
457b9b2e0b2SEd Tanous                     std::size_t lastIndex = path.rfind("/");
458b9b2e0b2SEd Tanous                     if (lastIndex == std::string::npos)
459b9b2e0b2SEd Tanous                     {
460b9b2e0b2SEd Tanous                         lastIndex = 0;
461b9b2e0b2SEd Tanous                     }
462b9b2e0b2SEd Tanous                     else
463b9b2e0b2SEd Tanous                     {
464b9b2e0b2SEd Tanous                         lastIndex += 1;
465b9b2e0b2SEd Tanous                     }
466b9b2e0b2SEd Tanous                     memberArray.push_back(
467b9b2e0b2SEd Tanous                         {{"@odata.id", "/redfish/v1/AccountService/Accounts/" +
468b9b2e0b2SEd Tanous                                            path.substr(lastIndex)}});
469b9b2e0b2SEd Tanous                 }
470b9b2e0b2SEd Tanous             },
471b9b2e0b2SEd Tanous             "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
472b9b2e0b2SEd Tanous             "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
473b9b2e0b2SEd Tanous     }
47404ae99ecSEd Tanous     void doPost(crow::Response& res, const crow::Request& req,
47504ae99ecSEd Tanous                 const std::vector<std::string>& params) override
47604ae99ecSEd Tanous     {
47704ae99ecSEd Tanous         auto asyncResp = std::make_shared<AsyncResp>(res);
47804ae99ecSEd Tanous 
4799712f8acSEd Tanous         std::string username;
4809712f8acSEd Tanous         std::string password;
481a24526dcSEd Tanous         std::optional<std::string> roleId("User");
482a24526dcSEd Tanous         std::optional<bool> enabled = true;
4839712f8acSEd Tanous         if (!json_util::readJson(req, res, "UserName", username, "Password",
4849712f8acSEd Tanous                                  password, "RoleId", roleId, "Enabled",
4859712f8acSEd Tanous                                  enabled))
48604ae99ecSEd Tanous         {
48704ae99ecSEd Tanous             return;
48804ae99ecSEd Tanous         }
48904ae99ecSEd Tanous 
49084e12cb7SAppaRao Puli         std::string priv = getRoleIdFromPrivilege(*roleId);
49184e12cb7SAppaRao Puli         if (priv.empty())
49204ae99ecSEd Tanous         {
493f12894f8SJason M. Bills             messages::propertyValueNotInList(asyncResp->res, *roleId, "RoleId");
49404ae99ecSEd Tanous             return;
49504ae99ecSEd Tanous         }
4969712f8acSEd Tanous         roleId = priv;
49704ae99ecSEd Tanous 
49804ae99ecSEd Tanous         crow::connections::systemBus->async_method_call(
4999712f8acSEd Tanous             [asyncResp, username, password{std::move(password)}](
50004ae99ecSEd Tanous                 const boost::system::error_code ec) {
50104ae99ecSEd Tanous                 if (ec)
50204ae99ecSEd Tanous                 {
50304ae99ecSEd Tanous                     messages::resourceAlreadyExists(
504f12894f8SJason M. Bills                         asyncResp->res, "#ManagerAccount.v1_0_3.ManagerAccount",
505f12894f8SJason M. Bills                         "UserName", username);
50604ae99ecSEd Tanous                     return;
50704ae99ecSEd Tanous                 }
50804ae99ecSEd Tanous 
50904ae99ecSEd Tanous                 if (!pamUpdatePassword(username, password))
51004ae99ecSEd Tanous                 {
51104ae99ecSEd Tanous                     // At this point we have a user that's been created, but the
51204ae99ecSEd Tanous                     // password set failed.  Something is wrong, so delete the
51304ae99ecSEd Tanous                     // user that we've already created
51404ae99ecSEd Tanous                     crow::connections::systemBus->async_method_call(
51504ae99ecSEd Tanous                         [asyncResp](const boost::system::error_code ec) {
51604ae99ecSEd Tanous                             if (ec)
51704ae99ecSEd Tanous                             {
518f12894f8SJason M. Bills                                 messages::internalError(asyncResp->res);
51904ae99ecSEd Tanous                                 return;
52004ae99ecSEd Tanous                             }
52104ae99ecSEd Tanous 
522f12894f8SJason M. Bills                             messages::invalidObject(asyncResp->res, "Password");
52304ae99ecSEd Tanous                         },
52404ae99ecSEd Tanous                         "xyz.openbmc_project.User.Manager",
52504ae99ecSEd Tanous                         "/xyz/openbmc_project/user/" + username,
52604ae99ecSEd Tanous                         "xyz.openbmc_project.Object.Delete", "Delete");
52704ae99ecSEd Tanous 
52804ae99ecSEd Tanous                     BMCWEB_LOG_ERROR << "pamUpdatePassword Failed";
52904ae99ecSEd Tanous                     return;
53004ae99ecSEd Tanous                 }
53104ae99ecSEd Tanous 
532f12894f8SJason M. Bills                 messages::created(asyncResp->res);
53304ae99ecSEd Tanous                 asyncResp->res.addHeader(
53404ae99ecSEd Tanous                     "Location",
53504ae99ecSEd Tanous                     "/redfish/v1/AccountService/Accounts/" + username);
53604ae99ecSEd Tanous             },
53704ae99ecSEd Tanous             "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
5389712f8acSEd Tanous             "xyz.openbmc_project.User.Manager", "CreateUser", username,
53904ae99ecSEd Tanous             std::array<const char*, 4>{"ipmi", "redfish", "ssh", "web"},
5409712f8acSEd Tanous             *roleId, *enabled);
54104ae99ecSEd Tanous     }
542b9b2e0b2SEd Tanous };
543b9b2e0b2SEd Tanous 
544a840879dSEd Tanous template <typename Callback>
545a840879dSEd Tanous inline void checkDbusPathExists(const std::string& path, Callback&& callback)
546a840879dSEd Tanous {
547a840879dSEd Tanous     using GetObjectType =
548a840879dSEd Tanous         std::vector<std::pair<std::string, std::vector<std::string>>>;
549a840879dSEd Tanous 
550a840879dSEd Tanous     crow::connections::systemBus->async_method_call(
551a840879dSEd Tanous         [callback{std::move(callback)}](const boost::system::error_code ec,
552a840879dSEd Tanous                                         const GetObjectType& object_names) {
55384e12cb7SAppaRao Puli             callback(!ec && object_names.size() != 0);
554a840879dSEd Tanous         },
555a840879dSEd Tanous         "xyz.openbmc_project.ObjectMapper",
556a840879dSEd Tanous         "/xyz/openbmc_project/object_mapper",
557a840879dSEd Tanous         "xyz.openbmc_project.ObjectMapper", "GetObject", path,
558a840879dSEd Tanous         std::array<std::string, 0>());
559a840879dSEd Tanous }
560a840879dSEd Tanous 
561b9b2e0b2SEd Tanous class ManagerAccount : public Node
562b9b2e0b2SEd Tanous {
563b9b2e0b2SEd Tanous   public:
564b9b2e0b2SEd Tanous     ManagerAccount(CrowApp& app) :
565b9b2e0b2SEd Tanous         Node(app, "/redfish/v1/AccountService/Accounts/<str>/", std::string())
566b9b2e0b2SEd Tanous     {
567b9b2e0b2SEd Tanous         entityPrivileges = {
568b9b2e0b2SEd Tanous             {boost::beast::http::verb::get,
569b9b2e0b2SEd Tanous              {{"ConfigureUsers"}, {"ConfigureManager"}, {"ConfigureSelf"}}},
570b9b2e0b2SEd Tanous             {boost::beast::http::verb::head, {{"Login"}}},
571b9b2e0b2SEd Tanous             {boost::beast::http::verb::patch, {{"ConfigureUsers"}}},
572b9b2e0b2SEd Tanous             {boost::beast::http::verb::put, {{"ConfigureUsers"}}},
573b9b2e0b2SEd Tanous             {boost::beast::http::verb::delete_, {{"ConfigureUsers"}}},
574b9b2e0b2SEd Tanous             {boost::beast::http::verb::post, {{"ConfigureUsers"}}}};
575b9b2e0b2SEd Tanous     }
576b9b2e0b2SEd Tanous 
577b9b2e0b2SEd Tanous   private:
578b9b2e0b2SEd Tanous     void doGet(crow::Response& res, const crow::Request& req,
579b9b2e0b2SEd Tanous                const std::vector<std::string>& params) override
580b9b2e0b2SEd Tanous     {
5810f74e643SEd Tanous         res.jsonValue = {
5820f74e643SEd Tanous             {"@odata.context",
5830f74e643SEd Tanous              "/redfish/v1/$metadata#ManagerAccount.ManagerAccount"},
5840f74e643SEd Tanous             {"@odata.type", "#ManagerAccount.v1_0_3.ManagerAccount"},
5850f74e643SEd Tanous             {"Name", "User Account"},
5860f74e643SEd Tanous             {"Description", "User Account"},
5870f74e643SEd Tanous             {"Password", nullptr},
58884e12cb7SAppaRao Puli             {"RoleId", "Administrator"}};
5890f74e643SEd Tanous 
590b9b2e0b2SEd Tanous         auto asyncResp = std::make_shared<AsyncResp>(res);
591b9b2e0b2SEd Tanous 
592b9b2e0b2SEd Tanous         if (params.size() != 1)
593b9b2e0b2SEd Tanous         {
594f12894f8SJason M. Bills             messages::internalError(asyncResp->res);
595b9b2e0b2SEd Tanous             return;
596b9b2e0b2SEd Tanous         }
597b9b2e0b2SEd Tanous 
598b9b2e0b2SEd Tanous         crow::connections::systemBus->async_method_call(
599b9b2e0b2SEd Tanous             [asyncResp, accountName{std::string(params[0])}](
600b9b2e0b2SEd Tanous                 const boost::system::error_code ec,
601b9b2e0b2SEd Tanous                 const ManagedObjectType& users) {
602b9b2e0b2SEd Tanous                 if (ec)
603b9b2e0b2SEd Tanous                 {
604f12894f8SJason M. Bills                     messages::internalError(asyncResp->res);
605b9b2e0b2SEd Tanous                     return;
606b9b2e0b2SEd Tanous                 }
60784e12cb7SAppaRao Puli                 auto userIt = users.begin();
608b9b2e0b2SEd Tanous 
60984e12cb7SAppaRao Puli                 for (; userIt != users.end(); userIt++)
610b9b2e0b2SEd Tanous                 {
61184e12cb7SAppaRao Puli                     if (boost::ends_with(userIt->first.str, "/" + accountName))
612b9b2e0b2SEd Tanous                     {
61384e12cb7SAppaRao Puli                         break;
614b9b2e0b2SEd Tanous                     }
615b9b2e0b2SEd Tanous                 }
61684e12cb7SAppaRao Puli                 if (userIt == users.end())
617b9b2e0b2SEd Tanous                 {
61884e12cb7SAppaRao Puli                     messages::resourceNotFound(asyncResp->res, "ManagerAccount",
61984e12cb7SAppaRao Puli                                                accountName);
62084e12cb7SAppaRao Puli                     return;
62184e12cb7SAppaRao Puli                 }
62284e12cb7SAppaRao Puli                 for (const auto& interface : userIt->second)
62365b0dc32SEd Tanous                 {
62465b0dc32SEd Tanous                     if (interface.first ==
62565b0dc32SEd Tanous                         "xyz.openbmc_project.User.Attributes")
62665b0dc32SEd Tanous                     {
62765b0dc32SEd Tanous                         for (const auto& property : interface.second)
62865b0dc32SEd Tanous                         {
62965b0dc32SEd Tanous                             if (property.first == "UserEnabled")
63065b0dc32SEd Tanous                             {
63165b0dc32SEd Tanous                                 const bool* userEnabled =
632abf2add6SEd Tanous                                     std::get_if<bool>(&property.second);
63365b0dc32SEd Tanous                                 if (userEnabled == nullptr)
63465b0dc32SEd Tanous                                 {
63565b0dc32SEd Tanous                                     BMCWEB_LOG_ERROR
63665b0dc32SEd Tanous                                         << "UserEnabled wasn't a bool";
63784e12cb7SAppaRao Puli                                     messages::internalError(asyncResp->res);
63884e12cb7SAppaRao Puli                                     return;
63965b0dc32SEd Tanous                                 }
64065b0dc32SEd Tanous                                 asyncResp->res.jsonValue["Enabled"] =
64165b0dc32SEd Tanous                                     *userEnabled;
64265b0dc32SEd Tanous                             }
64365b0dc32SEd Tanous                             else if (property.first ==
64465b0dc32SEd Tanous                                      "UserLockedForFailedAttempt")
64565b0dc32SEd Tanous                             {
64665b0dc32SEd Tanous                                 const bool* userLocked =
647abf2add6SEd Tanous                                     std::get_if<bool>(&property.second);
64865b0dc32SEd Tanous                                 if (userLocked == nullptr)
64965b0dc32SEd Tanous                                 {
65084e12cb7SAppaRao Puli                                     BMCWEB_LOG_ERROR << "UserLockedForF"
65184e12cb7SAppaRao Puli                                                         "ailedAttempt "
65284e12cb7SAppaRao Puli                                                         "wasn't a bool";
65384e12cb7SAppaRao Puli                                     messages::internalError(asyncResp->res);
65484e12cb7SAppaRao Puli                                     return;
65565b0dc32SEd Tanous                                 }
65665b0dc32SEd Tanous                                 asyncResp->res.jsonValue["Locked"] =
65765b0dc32SEd Tanous                                     *userLocked;
65824c8542dSRatan Gupta                                 asyncResp->res.jsonValue
65924c8542dSRatan Gupta                                     ["Locked@Redfish.AllowableValues"] = {
6604d64ce34SGunnar Mills                                     "false"};
66165b0dc32SEd Tanous                             }
66284e12cb7SAppaRao Puli                             else if (property.first == "UserPrivilege")
66384e12cb7SAppaRao Puli                             {
66484e12cb7SAppaRao Puli                                 const std::string* userRolePtr =
665abf2add6SEd Tanous                                     std::get_if<std::string>(&property.second);
66684e12cb7SAppaRao Puli                                 if (userRolePtr == nullptr)
66784e12cb7SAppaRao Puli                                 {
66884e12cb7SAppaRao Puli                                     BMCWEB_LOG_ERROR
66984e12cb7SAppaRao Puli                                         << "UserPrivilege wasn't a "
67084e12cb7SAppaRao Puli                                            "string";
67184e12cb7SAppaRao Puli                                     messages::internalError(asyncResp->res);
67284e12cb7SAppaRao Puli                                     return;
67384e12cb7SAppaRao Puli                                 }
67484e12cb7SAppaRao Puli                                 std::string priv =
67584e12cb7SAppaRao Puli                                     getPrivilegeFromRoleId(*userRolePtr);
67684e12cb7SAppaRao Puli                                 if (priv.empty())
67784e12cb7SAppaRao Puli                                 {
67884e12cb7SAppaRao Puli                                     BMCWEB_LOG_ERROR << "Invalid user role";
67984e12cb7SAppaRao Puli                                     messages::internalError(asyncResp->res);
68084e12cb7SAppaRao Puli                                     return;
68184e12cb7SAppaRao Puli                                 }
68284e12cb7SAppaRao Puli                                 asyncResp->res.jsonValue["RoleId"] = priv;
68384e12cb7SAppaRao Puli 
68484e12cb7SAppaRao Puli                                 asyncResp->res.jsonValue["Links"]["Role"] = {
68584e12cb7SAppaRao Puli                                     {"@odata.id", "/redfish/v1/AccountService/"
68684e12cb7SAppaRao Puli                                                   "Roles/" +
68784e12cb7SAppaRao Puli                                                       priv}};
68884e12cb7SAppaRao Puli                             }
68965b0dc32SEd Tanous                         }
69065b0dc32SEd Tanous                     }
69165b0dc32SEd Tanous                 }
69265b0dc32SEd Tanous 
693b9b2e0b2SEd Tanous                 asyncResp->res.jsonValue["@odata.id"] =
69484e12cb7SAppaRao Puli                     "/redfish/v1/AccountService/Accounts/" + accountName;
695b9b2e0b2SEd Tanous                 asyncResp->res.jsonValue["Id"] = accountName;
696b9b2e0b2SEd Tanous                 asyncResp->res.jsonValue["UserName"] = accountName;
697b9b2e0b2SEd Tanous             },
698b9b2e0b2SEd Tanous             "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
699b9b2e0b2SEd Tanous             "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
700b9b2e0b2SEd Tanous     }
701a840879dSEd Tanous 
702a840879dSEd Tanous     void doPatch(crow::Response& res, const crow::Request& req,
703a840879dSEd Tanous                  const std::vector<std::string>& params) override
704a840879dSEd Tanous     {
705a840879dSEd Tanous         auto asyncResp = std::make_shared<AsyncResp>(res);
706a840879dSEd Tanous         if (params.size() != 1)
707a840879dSEd Tanous         {
708f12894f8SJason M. Bills             messages::internalError(asyncResp->res);
709a840879dSEd Tanous             return;
710a840879dSEd Tanous         }
711a840879dSEd Tanous 
712a24526dcSEd Tanous         std::optional<std::string> newUserName;
713a24526dcSEd Tanous         std::optional<std::string> password;
714a24526dcSEd Tanous         std::optional<bool> enabled;
715a24526dcSEd Tanous         std::optional<std::string> roleId;
71624c8542dSRatan Gupta         std::optional<bool> locked;
71784e12cb7SAppaRao Puli         if (!json_util::readJson(req, res, "UserName", newUserName, "Password",
71824c8542dSRatan Gupta                                  password, "RoleId", roleId, "Enabled", enabled,
71924c8542dSRatan Gupta                                  "Locked", locked))
720a840879dSEd Tanous         {
721a840879dSEd Tanous             return;
722a840879dSEd Tanous         }
723a840879dSEd Tanous 
72484e12cb7SAppaRao Puli         const std::string& username = params[0];
72584e12cb7SAppaRao Puli 
72684e12cb7SAppaRao Puli         if (!newUserName)
727a840879dSEd Tanous         {
72884e12cb7SAppaRao Puli             // If the username isn't being updated, we can update the properties
72984e12cb7SAppaRao Puli             // directly
73024c8542dSRatan Gupta             updateUserProperties(asyncResp, username, password, enabled, roleId,
73124c8542dSRatan Gupta                                  locked);
73284e12cb7SAppaRao Puli             return;
73384e12cb7SAppaRao Puli         }
73484e12cb7SAppaRao Puli         else
73584e12cb7SAppaRao Puli         {
73684e12cb7SAppaRao Puli             crow::connections::systemBus->async_method_call(
73784e12cb7SAppaRao Puli                 [this, asyncResp, username, password(std::move(password)),
73884e12cb7SAppaRao Puli                  roleId(std::move(roleId)), enabled(std::move(enabled)),
73924c8542dSRatan Gupta                  newUser{std::string(*newUserName)}, locked(std::move(locked))](
74084e12cb7SAppaRao Puli                     const boost::system::error_code ec) {
74184e12cb7SAppaRao Puli                     if (ec)
74284e12cb7SAppaRao Puli                     {
74384e12cb7SAppaRao Puli                         BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
744a840879dSEd Tanous                         messages::resourceNotFound(
74584e12cb7SAppaRao Puli                             asyncResp->res,
74684e12cb7SAppaRao Puli                             "#ManagerAccount.v1_0_3.ManagerAccount", username);
747a840879dSEd Tanous                         return;
748a840879dSEd Tanous                     }
749a840879dSEd Tanous 
75084e12cb7SAppaRao Puli                     updateUserProperties(asyncResp, newUser, password, enabled,
75124c8542dSRatan Gupta                                          roleId, locked);
75284e12cb7SAppaRao Puli                 },
75384e12cb7SAppaRao Puli                 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
75484e12cb7SAppaRao Puli                 "xyz.openbmc_project.User.Manager", "RenameUser", username,
75584e12cb7SAppaRao Puli                 *newUserName);
75684e12cb7SAppaRao Puli         }
75784e12cb7SAppaRao Puli     }
75884e12cb7SAppaRao Puli 
75984e12cb7SAppaRao Puli     void updateUserProperties(std::shared_ptr<AsyncResp> asyncResp,
76084e12cb7SAppaRao Puli                               const std::string& username,
761a24526dcSEd Tanous                               std::optional<std::string> password,
762a24526dcSEd Tanous                               std::optional<bool> enabled,
76324c8542dSRatan Gupta                               std::optional<std::string> roleId,
76424c8542dSRatan Gupta                               std::optional<bool> locked)
76584e12cb7SAppaRao Puli     {
7669712f8acSEd Tanous         if (password)
767a840879dSEd Tanous         {
7689712f8acSEd Tanous             if (!pamUpdatePassword(username, *password))
769a840879dSEd Tanous             {
770a840879dSEd Tanous                 BMCWEB_LOG_ERROR << "pamUpdatePassword Failed";
771f12894f8SJason M. Bills                 messages::internalError(asyncResp->res);
772a840879dSEd Tanous                 return;
773a840879dSEd Tanous             }
774a840879dSEd Tanous         }
775a840879dSEd Tanous 
77624c8542dSRatan Gupta         std::string dbusObjectPath = "/xyz/openbmc_project/user/" + username;
77724c8542dSRatan Gupta         dbus::utility::escapePathForDbus(dbusObjectPath);
77824c8542dSRatan Gupta 
77924c8542dSRatan Gupta         checkDbusPathExists(
78024c8542dSRatan Gupta             dbusObjectPath,
78124c8542dSRatan Gupta             [dbusObjectPath(std::move(dbusObjectPath)), username,
78224c8542dSRatan Gupta              password(std::move(password)), roleId(std::move(roleId)),
78324c8542dSRatan Gupta              enabled(std::move(enabled)), locked(std::move(locked)),
78424c8542dSRatan Gupta              asyncResp{std::move(asyncResp)}](int rc) {
78524c8542dSRatan Gupta                 if (!rc)
78624c8542dSRatan Gupta                 {
78724c8542dSRatan Gupta                     messages::invalidObject(asyncResp->res, username.c_str());
78824c8542dSRatan Gupta                     return;
78924c8542dSRatan Gupta                 }
7909712f8acSEd Tanous                 if (enabled)
791a840879dSEd Tanous                 {
792a840879dSEd Tanous                     crow::connections::systemBus->async_method_call(
793a840879dSEd Tanous                         [asyncResp](const boost::system::error_code ec) {
794a840879dSEd Tanous                             if (ec)
795a840879dSEd Tanous                             {
79624c8542dSRatan Gupta                                 BMCWEB_LOG_ERROR << "D-Bus responses error: "
79724c8542dSRatan Gupta                                                  << ec;
798f12894f8SJason M. Bills                                 messages::internalError(asyncResp->res);
799a840879dSEd Tanous                                 return;
800a840879dSEd Tanous                             }
80184e12cb7SAppaRao Puli                             messages::success(asyncResp->res);
80284e12cb7SAppaRao Puli                             return;
80384e12cb7SAppaRao Puli                         },
80484e12cb7SAppaRao Puli                         "xyz.openbmc_project.User.Manager",
80524c8542dSRatan Gupta                         dbusObjectPath.c_str(),
80684e12cb7SAppaRao Puli                         "org.freedesktop.DBus.Properties", "Set",
80784e12cb7SAppaRao Puli                         "xyz.openbmc_project.User.Attributes", "UserEnabled",
808abf2add6SEd Tanous                         std::variant<bool>{*enabled});
80984e12cb7SAppaRao Puli                 }
81084e12cb7SAppaRao Puli 
81184e12cb7SAppaRao Puli                 if (roleId)
81284e12cb7SAppaRao Puli                 {
81384e12cb7SAppaRao Puli                     std::string priv = getRoleIdFromPrivilege(*roleId);
81484e12cb7SAppaRao Puli                     if (priv.empty())
81584e12cb7SAppaRao Puli                     {
81624c8542dSRatan Gupta                         messages::propertyValueNotInList(asyncResp->res,
81724c8542dSRatan Gupta                                                          *roleId, "RoleId");
81884e12cb7SAppaRao Puli                         return;
81984e12cb7SAppaRao Puli                     }
82084e12cb7SAppaRao Puli 
82184e12cb7SAppaRao Puli                     crow::connections::systemBus->async_method_call(
82284e12cb7SAppaRao Puli                         [asyncResp](const boost::system::error_code ec) {
82384e12cb7SAppaRao Puli                             if (ec)
82484e12cb7SAppaRao Puli                             {
82524c8542dSRatan Gupta                                 BMCWEB_LOG_ERROR << "D-Bus responses error: "
82624c8542dSRatan Gupta                                                  << ec;
82784e12cb7SAppaRao Puli                                 messages::internalError(asyncResp->res);
82884e12cb7SAppaRao Puli                                 return;
82984e12cb7SAppaRao Puli                             }
830f12894f8SJason M. Bills                             messages::success(asyncResp->res);
831a840879dSEd Tanous                         },
832a840879dSEd Tanous                         "xyz.openbmc_project.User.Manager",
83324c8542dSRatan Gupta                         dbusObjectPath.c_str(),
834a840879dSEd Tanous                         "org.freedesktop.DBus.Properties", "Set",
83584e12cb7SAppaRao Puli                         "xyz.openbmc_project.User.Attributes", "UserPrivilege",
836abf2add6SEd Tanous                         std::variant<std::string>{priv});
837a840879dSEd Tanous                 }
83824c8542dSRatan Gupta 
83924c8542dSRatan Gupta                 if (locked)
84024c8542dSRatan Gupta                 {
84124c8542dSRatan Gupta                     // admin can unlock the account which is locked by
84224c8542dSRatan Gupta                     // successive authentication failures but admin should not
84324c8542dSRatan Gupta                     // be allowed to lock an account.
84424c8542dSRatan Gupta                     if (*locked)
84524c8542dSRatan Gupta                     {
84624c8542dSRatan Gupta                         messages::propertyValueNotInList(asyncResp->res, "true",
84724c8542dSRatan Gupta                                                          "Locked");
84824c8542dSRatan Gupta                         return;
84924c8542dSRatan Gupta                     }
85024c8542dSRatan Gupta 
85124c8542dSRatan Gupta                     crow::connections::systemBus->async_method_call(
85224c8542dSRatan Gupta                         [asyncResp](const boost::system::error_code ec) {
85324c8542dSRatan Gupta                             if (ec)
85424c8542dSRatan Gupta                             {
85524c8542dSRatan Gupta                                 BMCWEB_LOG_ERROR << "D-Bus responses error: "
85624c8542dSRatan Gupta                                                  << ec;
85724c8542dSRatan Gupta                                 messages::internalError(asyncResp->res);
85824c8542dSRatan Gupta                                 return;
85924c8542dSRatan Gupta                             }
86024c8542dSRatan Gupta                             messages::success(asyncResp->res);
86124c8542dSRatan Gupta                             return;
86224c8542dSRatan Gupta                         },
86324c8542dSRatan Gupta                         "xyz.openbmc_project.User.Manager",
86424c8542dSRatan Gupta                         dbusObjectPath.c_str(),
86524c8542dSRatan Gupta                         "org.freedesktop.DBus.Properties", "Set",
86624c8542dSRatan Gupta                         "xyz.openbmc_project.User.Attributes",
86724c8542dSRatan Gupta                         "UserLockedForFailedAttempt",
86824c8542dSRatan Gupta                         sdbusplus::message::variant<bool>{*locked});
86924c8542dSRatan Gupta                 }
87024c8542dSRatan Gupta             });
871a840879dSEd Tanous     }
87206e086d9SEd Tanous 
87306e086d9SEd Tanous     void doDelete(crow::Response& res, const crow::Request& req,
87406e086d9SEd Tanous                   const std::vector<std::string>& params) override
87506e086d9SEd Tanous     {
87606e086d9SEd Tanous         auto asyncResp = std::make_shared<AsyncResp>(res);
87706e086d9SEd Tanous 
87806e086d9SEd Tanous         if (params.size() != 1)
87906e086d9SEd Tanous         {
880f12894f8SJason M. Bills             messages::internalError(asyncResp->res);
88106e086d9SEd Tanous             return;
88206e086d9SEd Tanous         }
88306e086d9SEd Tanous 
88406e086d9SEd Tanous         const std::string userPath = "/xyz/openbmc_project/user/" + params[0];
88506e086d9SEd Tanous 
88606e086d9SEd Tanous         crow::connections::systemBus->async_method_call(
88706e086d9SEd Tanous             [asyncResp, username{std::move(params[0])}](
88806e086d9SEd Tanous                 const boost::system::error_code ec) {
88906e086d9SEd Tanous                 if (ec)
89006e086d9SEd Tanous                 {
89106e086d9SEd Tanous                     messages::resourceNotFound(
892f12894f8SJason M. Bills                         asyncResp->res, "#ManagerAccount.v1_0_3.ManagerAccount",
893f12894f8SJason M. Bills                         username);
89406e086d9SEd Tanous                     return;
89506e086d9SEd Tanous                 }
89606e086d9SEd Tanous 
897f12894f8SJason M. Bills                 messages::accountRemoved(asyncResp->res);
89806e086d9SEd Tanous             },
89906e086d9SEd Tanous             "xyz.openbmc_project.User.Manager", userPath,
90006e086d9SEd Tanous             "xyz.openbmc_project.Object.Delete", "Delete");
90106e086d9SEd Tanous     }
90284e12cb7SAppaRao Puli };
90388d16c9aSLewanczyk, Dawid 
90488d16c9aSLewanczyk, Dawid } // namespace redfish
905