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 286973a582SRatan Gupta constexpr const char* ldapConfigObject = 296973a582SRatan Gupta "/xyz/openbmc_project/user/ldap/openldap"; 30ab828d7cSRatan Gupta constexpr const char* ADConfigObject = 31ab828d7cSRatan Gupta "/xyz/openbmc_project/user/ldap/active_directory"; 32ab828d7cSRatan Gupta 336973a582SRatan Gupta constexpr const char* ldapRootObject = "/xyz/openbmc_project/user/ldap"; 346973a582SRatan Gupta constexpr const char* ldapDbusService = "xyz.openbmc_project.Ldap.Config"; 356973a582SRatan Gupta constexpr const char* ldapConfigInterface = 366973a582SRatan Gupta "xyz.openbmc_project.User.Ldap.Config"; 376973a582SRatan Gupta constexpr const char* ldapCreateInterface = 386973a582SRatan Gupta "xyz.openbmc_project.User.Ldap.Create"; 396973a582SRatan Gupta constexpr const char* ldapEnableInterface = "xyz.openbmc_project.Object.Enable"; 406973a582SRatan Gupta constexpr const char* dbusObjManagerIntf = "org.freedesktop.DBus.ObjectManager"; 416973a582SRatan Gupta constexpr const char* propertyInterface = "org.freedesktop.DBus.Properties"; 426973a582SRatan Gupta constexpr const char* mapperBusName = "xyz.openbmc_project.ObjectMapper"; 436973a582SRatan Gupta constexpr const char* mapperObjectPath = "/xyz/openbmc_project/object_mapper"; 446973a582SRatan Gupta constexpr const char* mapperIntf = "xyz.openbmc_project.ObjectMapper"; 456973a582SRatan Gupta 466973a582SRatan Gupta struct LDAPConfigData 476973a582SRatan Gupta { 486973a582SRatan Gupta std::string uri{}; 496973a582SRatan Gupta std::string bindDN{}; 506973a582SRatan Gupta std::string baseDN{}; 516973a582SRatan Gupta std::string searchScope{}; 526973a582SRatan Gupta std::string serverType{}; 536973a582SRatan Gupta bool serviceEnabled = false; 546973a582SRatan Gupta std::string userNameAttribute{}; 556973a582SRatan Gupta std::string groupAttribute{}; 566973a582SRatan Gupta }; 576973a582SRatan Gupta 58b9b2e0b2SEd Tanous using ManagedObjectType = std::vector<std::pair< 59b9b2e0b2SEd Tanous sdbusplus::message::object_path, 60b9b2e0b2SEd Tanous boost::container::flat_map< 61abf2add6SEd Tanous std::string, boost::container::flat_map< 62abf2add6SEd Tanous std::string, std::variant<bool, std::string>>>>>; 636973a582SRatan Gupta using GetObjectType = 646973a582SRatan Gupta std::vector<std::pair<std::string, std::vector<std::string>>>; 6584e12cb7SAppaRao Puli 66ae29b8c4SAdriana Kobylak inline std::string getPrivilegeFromRoleId(std::string_view role) 6784e12cb7SAppaRao Puli { 6884e12cb7SAppaRao Puli if (role == "priv-admin") 6984e12cb7SAppaRao Puli { 7084e12cb7SAppaRao Puli return "Administrator"; 7184e12cb7SAppaRao Puli } 7284e12cb7SAppaRao Puli else if (role == "priv-callback") 7384e12cb7SAppaRao Puli { 7484e12cb7SAppaRao Puli return "Callback"; 7584e12cb7SAppaRao Puli } 7684e12cb7SAppaRao Puli else if (role == "priv-user") 7784e12cb7SAppaRao Puli { 7884e12cb7SAppaRao Puli return "User"; 7984e12cb7SAppaRao Puli } 8084e12cb7SAppaRao Puli else if (role == "priv-operator") 8184e12cb7SAppaRao Puli { 8284e12cb7SAppaRao Puli return "Operator"; 8384e12cb7SAppaRao Puli } 8484e12cb7SAppaRao Puli return ""; 8584e12cb7SAppaRao Puli } 86ae29b8c4SAdriana Kobylak inline std::string getRoleIdFromPrivilege(std::string_view role) 8784e12cb7SAppaRao Puli { 8884e12cb7SAppaRao Puli if (role == "Administrator") 8984e12cb7SAppaRao Puli { 9084e12cb7SAppaRao Puli return "priv-admin"; 9184e12cb7SAppaRao Puli } 9284e12cb7SAppaRao Puli else if (role == "Callback") 9384e12cb7SAppaRao Puli { 9484e12cb7SAppaRao Puli return "priv-callback"; 9584e12cb7SAppaRao Puli } 9684e12cb7SAppaRao Puli else if (role == "User") 9784e12cb7SAppaRao Puli { 9884e12cb7SAppaRao Puli return "priv-user"; 9984e12cb7SAppaRao Puli } 10084e12cb7SAppaRao Puli else if (role == "Operator") 10184e12cb7SAppaRao Puli { 10284e12cb7SAppaRao Puli return "priv-operator"; 10384e12cb7SAppaRao Puli } 10484e12cb7SAppaRao Puli return ""; 10584e12cb7SAppaRao Puli } 106b9b2e0b2SEd Tanous 1076973a582SRatan Gupta void parseLDAPConfigData(nlohmann::json& json_response, 108ab828d7cSRatan Gupta const LDAPConfigData& confData, 109ab828d7cSRatan Gupta const std::string& ldapType) 1106973a582SRatan Gupta { 111ab828d7cSRatan Gupta std::string service = 112ab828d7cSRatan Gupta (ldapType == "LDAP") ? "LDAPService" : "ActiveDirectoryService"; 113*37cce918SMarri Devender Rao nlohmann::json ldap = { 1146973a582SRatan Gupta {"AccountProviderType", service}, 1156973a582SRatan Gupta {"ServiceEnabled", confData.serviceEnabled}, 1166973a582SRatan Gupta {"ServiceAddresses", nlohmann::json::array({confData.uri})}, 1176973a582SRatan Gupta {"Authentication", 1186973a582SRatan Gupta {{"AuthenticationType", "UsernameAndPassword"}, 1196973a582SRatan Gupta {"Username", confData.bindDN}, 1206973a582SRatan Gupta {"Password", nullptr}}}, 1216973a582SRatan Gupta {"LDAPService", 1226973a582SRatan Gupta {{"SearchSettings", 1236973a582SRatan Gupta {{"BaseDistinguishedNames", 1246973a582SRatan Gupta nlohmann::json::array({confData.baseDN})}, 1256973a582SRatan Gupta {"UsernameAttribute", confData.userNameAttribute}, 1266973a582SRatan Gupta {"GroupsAttribute", confData.groupAttribute}}}}}, 1276973a582SRatan Gupta }; 128*37cce918SMarri Devender Rao json_response[ldapType].update(std::move(ldap)); 1296973a582SRatan Gupta } 1306973a582SRatan Gupta 1316973a582SRatan Gupta /** 1326973a582SRatan Gupta * Function that retrieves all properties for LDAP config object 1336973a582SRatan Gupta * into JSON 1346973a582SRatan Gupta */ 1356973a582SRatan Gupta template <typename CallbackFunc> 1366973a582SRatan Gupta inline void getLDAPConfigData(const std::string& ldapType, 1376973a582SRatan Gupta CallbackFunc&& callback) 1386973a582SRatan Gupta { 1396973a582SRatan Gupta auto getConfig = [callback, 1406973a582SRatan Gupta ldapType](const boost::system::error_code error_code, 1416973a582SRatan Gupta const ManagedObjectType& ldapObjects) { 1426973a582SRatan Gupta LDAPConfigData confData{}; 1436973a582SRatan Gupta if (error_code) 1446973a582SRatan Gupta { 145ab828d7cSRatan Gupta callback(false, confData, ldapType); 1466973a582SRatan Gupta BMCWEB_LOG_ERROR << "D-Bus responses error: " << error_code; 1476973a582SRatan Gupta return; 1486973a582SRatan Gupta } 149ab828d7cSRatan Gupta 150ab828d7cSRatan Gupta std::string ldapDbusType; 151ab828d7cSRatan Gupta if (ldapType == "LDAP") 152ab828d7cSRatan Gupta { 153ab828d7cSRatan Gupta ldapDbusType = "xyz.openbmc_project.User.Ldap.Config.Type.OpenLdap"; 154ab828d7cSRatan Gupta } 155ab828d7cSRatan Gupta else if (ldapType == "ActiveDirectory") 156ab828d7cSRatan Gupta { 157ab828d7cSRatan Gupta ldapDbusType = "xyz.openbmc_project.User.Ldap.Config.Type." 158ab828d7cSRatan Gupta "ActiveDirectory"; 159ab828d7cSRatan Gupta } 160ab828d7cSRatan Gupta else 161ab828d7cSRatan Gupta { 162ab828d7cSRatan Gupta BMCWEB_LOG_ERROR << "Can't get the DbusType for the given type=" 163ab828d7cSRatan Gupta << ldapType; 164ab828d7cSRatan Gupta callback(false, confData, ldapType); 165ab828d7cSRatan Gupta return; 166ab828d7cSRatan Gupta } 167ab828d7cSRatan Gupta 168ab828d7cSRatan Gupta std::string ldapEnableInterfaceStr = ldapEnableInterface; 169ab828d7cSRatan Gupta std::string ldapConfigInterfaceStr = ldapConfigInterface; 170ab828d7cSRatan Gupta 1716973a582SRatan Gupta for (const auto& object : ldapObjects) 1726973a582SRatan Gupta { 173ab828d7cSRatan Gupta // let's find the object whose ldap type is equal to the given type 174ab828d7cSRatan Gupta auto intfit = object.second.find(ldapConfigInterfaceStr); 175ab828d7cSRatan Gupta if (intfit == object.second.end()) 1766973a582SRatan Gupta { 177ab828d7cSRatan Gupta continue; 178ab828d7cSRatan Gupta } 179ab828d7cSRatan Gupta auto propit = intfit->second.find("LDAPType"); 180ab828d7cSRatan Gupta if (propit == intfit->second.end()) 181ab828d7cSRatan Gupta { 182ab828d7cSRatan Gupta continue; 183ab828d7cSRatan Gupta } 184ab828d7cSRatan Gupta 185ab828d7cSRatan Gupta const std::string* value = 186ab828d7cSRatan Gupta std::get_if<std::string>(&(propit->second)); 187ab828d7cSRatan Gupta if (value == nullptr || (*value) != ldapDbusType) 188ab828d7cSRatan Gupta { 189ab828d7cSRatan Gupta 190ab828d7cSRatan Gupta // this is not the interested configuration, 191ab828d7cSRatan Gupta // let's move on to the other configuration. 192ab828d7cSRatan Gupta continue; 193ab828d7cSRatan Gupta } 194ab828d7cSRatan Gupta else 195ab828d7cSRatan Gupta { 196ab828d7cSRatan Gupta confData.serverType = *value; 197ab828d7cSRatan Gupta } 198ab828d7cSRatan Gupta 1996973a582SRatan Gupta for (const auto& interface : object.second) 2006973a582SRatan Gupta { 2016973a582SRatan Gupta if (interface.first == ldapEnableInterfaceStr) 2026973a582SRatan Gupta { 2036973a582SRatan Gupta // rest of the properties are string. 2046973a582SRatan Gupta for (const auto& property : interface.second) 2056973a582SRatan Gupta { 2066973a582SRatan Gupta if (property.first == "Enabled") 2076973a582SRatan Gupta { 2086973a582SRatan Gupta const bool* value = 2096973a582SRatan Gupta std::get_if<bool>(&property.second); 2106973a582SRatan Gupta if (value == nullptr) 2116973a582SRatan Gupta { 2126973a582SRatan Gupta continue; 2136973a582SRatan Gupta } 2146973a582SRatan Gupta confData.serviceEnabled = *value; 2156973a582SRatan Gupta break; 2166973a582SRatan Gupta } 2176973a582SRatan Gupta } 2186973a582SRatan Gupta } 2196973a582SRatan Gupta else if (interface.first == ldapConfigInterfaceStr) 2206973a582SRatan Gupta { 2216973a582SRatan Gupta 2226973a582SRatan Gupta for (const auto& property : interface.second) 2236973a582SRatan Gupta { 2246973a582SRatan Gupta const std::string* value = 2256973a582SRatan Gupta std::get_if<std::string>(&property.second); 2266973a582SRatan Gupta if (value == nullptr) 2276973a582SRatan Gupta { 2286973a582SRatan Gupta continue; 2296973a582SRatan Gupta } 2306973a582SRatan Gupta if (property.first == "LDAPServerURI") 2316973a582SRatan Gupta { 2326973a582SRatan Gupta confData.uri = *value; 2336973a582SRatan Gupta } 2346973a582SRatan Gupta else if (property.first == "LDAPBindDN") 2356973a582SRatan Gupta { 2366973a582SRatan Gupta confData.bindDN = *value; 2376973a582SRatan Gupta } 2386973a582SRatan Gupta else if (property.first == "LDAPBaseDN") 2396973a582SRatan Gupta { 2406973a582SRatan Gupta confData.baseDN = *value; 2416973a582SRatan Gupta } 2426973a582SRatan Gupta else if (property.first == "LDAPSearchScope") 2436973a582SRatan Gupta { 2446973a582SRatan Gupta confData.searchScope = *value; 2456973a582SRatan Gupta } 2466973a582SRatan Gupta else if (property.first == "GroupNameAttribute") 2476973a582SRatan Gupta { 2486973a582SRatan Gupta confData.groupAttribute = *value; 2496973a582SRatan Gupta } 2506973a582SRatan Gupta else if (property.first == "UserNameAttribute") 2516973a582SRatan Gupta { 2526973a582SRatan Gupta confData.userNameAttribute = *value; 2536973a582SRatan Gupta } 2546973a582SRatan Gupta } 2556973a582SRatan Gupta } 2566973a582SRatan Gupta } 257ab828d7cSRatan Gupta if (confData.serverType == ldapDbusType) 258ab828d7cSRatan Gupta { 259ab828d7cSRatan Gupta callback(true, confData, ldapType); 2606973a582SRatan Gupta break; 2616973a582SRatan Gupta } 2626973a582SRatan Gupta } 2636973a582SRatan Gupta }; 264ab828d7cSRatan Gupta auto getServiceName = [callback, ldapType, getConfig(std::move(getConfig))]( 2656973a582SRatan Gupta const boost::system::error_code ec, 2666973a582SRatan Gupta const GetObjectType& resp) { 2676973a582SRatan Gupta LDAPConfigData confData{}; 2686973a582SRatan Gupta if (ec || resp.empty()) 2696973a582SRatan Gupta { 2706973a582SRatan Gupta BMCWEB_LOG_ERROR 2716973a582SRatan Gupta << "DBUS response error during getting of service name: " << ec; 272ab828d7cSRatan Gupta callback(false, confData, ldapType); 2736973a582SRatan Gupta return; 2746973a582SRatan Gupta } 2756973a582SRatan Gupta std::string service = resp.begin()->first; 2766973a582SRatan Gupta crow::connections::systemBus->async_method_call( 2776973a582SRatan Gupta std::move(getConfig), service, ldapRootObject, dbusObjManagerIntf, 2786973a582SRatan Gupta "GetManagedObjects"); 2796973a582SRatan Gupta }; 2806973a582SRatan Gupta 2816973a582SRatan Gupta const std::array<std::string, 2> interfaces = {ldapEnableInterface, 2826973a582SRatan Gupta ldapConfigInterface}; 2836973a582SRatan Gupta 2846973a582SRatan Gupta crow::connections::systemBus->async_method_call( 2856973a582SRatan Gupta std::move(getServiceName), mapperBusName, mapperObjectPath, mapperIntf, 2866973a582SRatan Gupta "GetObject", ldapConfigObject, interfaces); 2876973a582SRatan Gupta } 2886973a582SRatan Gupta 2891abe55efSEd Tanous class AccountService : public Node 2901abe55efSEd Tanous { 29188d16c9aSLewanczyk, Dawid public: 2921abe55efSEd Tanous AccountService(CrowApp& app) : Node(app, "/redfish/v1/AccountService/") 2931abe55efSEd Tanous { 2943ebd75f7SEd Tanous entityPrivileges = { 2954b1b8683SBorawski.Lukasz {boost::beast::http::verb::get, 2964b1b8683SBorawski.Lukasz {{"ConfigureUsers"}, {"ConfigureManager"}}}, 297e0d918bcSEd Tanous {boost::beast::http::verb::head, {{"Login"}}}, 298e0d918bcSEd Tanous {boost::beast::http::verb::patch, {{"ConfigureUsers"}}}, 299e0d918bcSEd Tanous {boost::beast::http::verb::put, {{"ConfigureUsers"}}}, 300e0d918bcSEd Tanous {boost::beast::http::verb::delete_, {{"ConfigureUsers"}}}, 301e0d918bcSEd Tanous {boost::beast::http::verb::post, {{"ConfigureUsers"}}}}; 30288d16c9aSLewanczyk, Dawid } 30388d16c9aSLewanczyk, Dawid 30488d16c9aSLewanczyk, Dawid private: 3058a07d286SRatan Gupta /** 3068a07d286SRatan Gupta * @brief parses the authentication section under the LDAP 3078a07d286SRatan Gupta * @param input JSON data 3088a07d286SRatan Gupta * @param asyncResp pointer to the JSON response 3098a07d286SRatan Gupta * @param userName userName to be filled from the given JSON. 3108a07d286SRatan Gupta * @param password password to be filled from the given JSON. 3118a07d286SRatan Gupta */ 3128a07d286SRatan Gupta void 3138a07d286SRatan Gupta parseLDAPAuthenticationJson(nlohmann::json input, 3148a07d286SRatan Gupta const std::shared_ptr<AsyncResp>& asyncResp, 3158a07d286SRatan Gupta std::optional<std::string>& username, 3168a07d286SRatan Gupta std::optional<std::string>& password) 3178a07d286SRatan Gupta { 3188a07d286SRatan Gupta std::optional<std::string> authType; 3198a07d286SRatan Gupta 3208a07d286SRatan Gupta if (!json_util::readJson(input, asyncResp->res, "AuthenticationType", 3218a07d286SRatan Gupta authType, "Username", username, "Password", 3228a07d286SRatan Gupta password)) 3238a07d286SRatan Gupta { 3248a07d286SRatan Gupta return; 3258a07d286SRatan Gupta } 3268a07d286SRatan Gupta if (!authType) 3278a07d286SRatan Gupta { 3288a07d286SRatan Gupta return; 3298a07d286SRatan Gupta } 3308a07d286SRatan Gupta if (*authType != "UsernameAndPassword") 3318a07d286SRatan Gupta { 3328a07d286SRatan Gupta messages::propertyValueNotInList(asyncResp->res, *authType, 3338a07d286SRatan Gupta "AuthenticationType"); 3348a07d286SRatan Gupta return; 3358a07d286SRatan Gupta } 3368a07d286SRatan Gupta } 3378a07d286SRatan Gupta /** 3388a07d286SRatan Gupta * @brief parses the LDAPService section under the LDAP 3398a07d286SRatan Gupta * @param input JSON data 3408a07d286SRatan Gupta * @param asyncResp pointer to the JSON response 3418a07d286SRatan Gupta * @param baseDNList baseDN to be filled from the given JSON. 3428a07d286SRatan Gupta * @param userNameAttribute userName to be filled from the given JSON. 3438a07d286SRatan Gupta * @param groupaAttribute password to be filled from the given JSON. 3448a07d286SRatan Gupta */ 3458a07d286SRatan Gupta 3468a07d286SRatan Gupta void parseLDAPServiceJson( 3478a07d286SRatan Gupta nlohmann::json input, const std::shared_ptr<AsyncResp>& asyncResp, 3488a07d286SRatan Gupta std::optional<std::vector<std::string>>& baseDNList, 3498a07d286SRatan Gupta std::optional<std::string>& userNameAttribute, 3508a07d286SRatan Gupta std::optional<std::string>& groupsAttribute) 3518a07d286SRatan Gupta { 3528a07d286SRatan Gupta std::optional<nlohmann::json> searchSettings; 3538a07d286SRatan Gupta 3548a07d286SRatan Gupta if (!json_util::readJson(input, asyncResp->res, "SearchSettings", 3558a07d286SRatan Gupta searchSettings)) 3568a07d286SRatan Gupta { 3578a07d286SRatan Gupta return; 3588a07d286SRatan Gupta } 3598a07d286SRatan Gupta if (!searchSettings) 3608a07d286SRatan Gupta { 3618a07d286SRatan Gupta return; 3628a07d286SRatan Gupta } 3638a07d286SRatan Gupta if (!json_util::readJson(*searchSettings, asyncResp->res, 3648a07d286SRatan Gupta "BaseDistinguishedNames", baseDNList, 3658a07d286SRatan Gupta "UsernameAttribute", userNameAttribute, 3668a07d286SRatan Gupta "GroupsAttribute", groupsAttribute)) 3678a07d286SRatan Gupta { 3688a07d286SRatan Gupta return; 3698a07d286SRatan Gupta } 3708a07d286SRatan Gupta } 3718a07d286SRatan Gupta /** 3728a07d286SRatan Gupta * @brief updates the LDAP server address and updates the 3738a07d286SRatan Gupta json response with the new value. 3748a07d286SRatan Gupta * @param serviceAddressList address to be updated. 3758a07d286SRatan Gupta * @param asyncResp pointer to the JSON response 3768a07d286SRatan Gupta * @param ldapServerElementName Type of LDAP 3778a07d286SRatan Gupta server(openLDAP/ActiveDirectory) 3788a07d286SRatan Gupta */ 3798a07d286SRatan Gupta 3808a07d286SRatan Gupta void handleServiceAddressPatch( 3818a07d286SRatan Gupta const std::vector<std::string>& serviceAddressList, 3828a07d286SRatan Gupta const std::shared_ptr<AsyncResp>& asyncResp, 3838a07d286SRatan Gupta const std::string& ldapServerElementName, 3848a07d286SRatan Gupta const std::string& ldapConfigObject) 3858a07d286SRatan Gupta { 3868a07d286SRatan Gupta crow::connections::systemBus->async_method_call( 3878a07d286SRatan Gupta [asyncResp, ldapServerElementName, 3888a07d286SRatan Gupta serviceAddressList](const boost::system::error_code ec) { 3898a07d286SRatan Gupta if (ec) 3908a07d286SRatan Gupta { 3918a07d286SRatan Gupta BMCWEB_LOG_DEBUG 3928a07d286SRatan Gupta << "Error Occured in updating the service address"; 3938a07d286SRatan Gupta messages::internalError(asyncResp->res); 3948a07d286SRatan Gupta return; 3958a07d286SRatan Gupta } 3968a07d286SRatan Gupta std::vector<std::string> modifiedserviceAddressList = { 3978a07d286SRatan Gupta serviceAddressList.front()}; 3988a07d286SRatan Gupta asyncResp->res 3998a07d286SRatan Gupta .jsonValue[ldapServerElementName]["ServiceAddresses"] = 4008a07d286SRatan Gupta modifiedserviceAddressList; 4018a07d286SRatan Gupta if ((serviceAddressList).size() > 1) 4028a07d286SRatan Gupta { 4038a07d286SRatan Gupta messages::propertyValueModified(asyncResp->res, 4048a07d286SRatan Gupta "ServiceAddresses", 4058a07d286SRatan Gupta serviceAddressList.front()); 4068a07d286SRatan Gupta } 4078a07d286SRatan Gupta BMCWEB_LOG_DEBUG << "Updated the service address"; 4088a07d286SRatan Gupta }, 4098a07d286SRatan Gupta ldapDbusService, ldapConfigObject, propertyInterface, "Set", 4108a07d286SRatan Gupta ldapConfigInterface, "LDAPServerURI", 4118a07d286SRatan Gupta std::variant<std::string>(serviceAddressList.front())); 4128a07d286SRatan Gupta } 4138a07d286SRatan Gupta /** 4148a07d286SRatan Gupta * @brief updates the LDAP Bind DN and updates the 4158a07d286SRatan Gupta json response with the new value. 4168a07d286SRatan Gupta * @param username name of the user which needs to be updated. 4178a07d286SRatan Gupta * @param asyncResp pointer to the JSON response 4188a07d286SRatan Gupta * @param ldapServerElementName Type of LDAP 4198a07d286SRatan Gupta server(openLDAP/ActiveDirectory) 4208a07d286SRatan Gupta */ 4218a07d286SRatan Gupta 4228a07d286SRatan Gupta void handleUserNamePatch(const std::string& username, 4238a07d286SRatan Gupta const std::shared_ptr<AsyncResp>& asyncResp, 4248a07d286SRatan Gupta const std::string& ldapServerElementName, 4258a07d286SRatan Gupta const std::string& ldapConfigObject) 4268a07d286SRatan Gupta { 4278a07d286SRatan Gupta crow::connections::systemBus->async_method_call( 4288a07d286SRatan Gupta [asyncResp, username, 4298a07d286SRatan Gupta ldapServerElementName](const boost::system::error_code ec) { 4308a07d286SRatan Gupta if (ec) 4318a07d286SRatan Gupta { 4328a07d286SRatan Gupta BMCWEB_LOG_DEBUG 4338a07d286SRatan Gupta << "Error occured in updating the username"; 4348a07d286SRatan Gupta messages::internalError(asyncResp->res); 4358a07d286SRatan Gupta return; 4368a07d286SRatan Gupta } 4378a07d286SRatan Gupta asyncResp->res.jsonValue[ldapServerElementName] 4388a07d286SRatan Gupta ["Authentication"]["Username"] = 4398a07d286SRatan Gupta username; 4408a07d286SRatan Gupta BMCWEB_LOG_DEBUG << "Updated the username"; 4418a07d286SRatan Gupta }, 4428a07d286SRatan Gupta ldapDbusService, ldapConfigObject, propertyInterface, "Set", 4438a07d286SRatan Gupta ldapConfigInterface, "LDAPBindDN", 4448a07d286SRatan Gupta std::variant<std::string>(username)); 4458a07d286SRatan Gupta } 4468a07d286SRatan Gupta 4478a07d286SRatan Gupta /** 4488a07d286SRatan Gupta * @brief updates the LDAP password 4498a07d286SRatan Gupta * @param password : ldap password which needs to be updated. 4508a07d286SRatan Gupta * @param asyncResp pointer to the JSON response 4518a07d286SRatan Gupta * @param ldapServerElementName Type of LDAP 4528a07d286SRatan Gupta * server(openLDAP/ActiveDirectory) 4538a07d286SRatan Gupta */ 4548a07d286SRatan Gupta 4558a07d286SRatan Gupta void handlePasswordPatch(const std::string& password, 4568a07d286SRatan Gupta const std::shared_ptr<AsyncResp>& asyncResp, 4578a07d286SRatan Gupta const std::string& ldapServerElementName, 4588a07d286SRatan Gupta const std::string& ldapConfigObject) 4598a07d286SRatan Gupta { 4608a07d286SRatan Gupta crow::connections::systemBus->async_method_call( 4618a07d286SRatan Gupta [asyncResp, password, 4628a07d286SRatan Gupta ldapServerElementName](const boost::system::error_code ec) { 4638a07d286SRatan Gupta if (ec) 4648a07d286SRatan Gupta { 4658a07d286SRatan Gupta BMCWEB_LOG_DEBUG 4668a07d286SRatan Gupta << "Error occured in updating the password"; 4678a07d286SRatan Gupta messages::internalError(asyncResp->res); 4688a07d286SRatan Gupta return; 4698a07d286SRatan Gupta } 4708a07d286SRatan Gupta asyncResp->res.jsonValue[ldapServerElementName] 4718a07d286SRatan Gupta ["Authentication"]["Password"] = ""; 4728a07d286SRatan Gupta BMCWEB_LOG_DEBUG << "Updated the password"; 4738a07d286SRatan Gupta }, 4748a07d286SRatan Gupta ldapDbusService, ldapConfigObject, propertyInterface, "Set", 4758a07d286SRatan Gupta ldapConfigInterface, "LDAPBindDNPassword", 4768a07d286SRatan Gupta std::variant<std::string>(password)); 4778a07d286SRatan Gupta } 4788a07d286SRatan Gupta 4798a07d286SRatan Gupta /** 4808a07d286SRatan Gupta * @brief updates the LDAP BaseDN and updates the 4818a07d286SRatan Gupta json response with the new value. 4828a07d286SRatan Gupta * @param baseDNList baseDN list which needs to be updated. 4838a07d286SRatan Gupta * @param asyncResp pointer to the JSON response 4848a07d286SRatan Gupta * @param ldapServerElementName Type of LDAP 4858a07d286SRatan Gupta server(openLDAP/ActiveDirectory) 4868a07d286SRatan Gupta */ 4878a07d286SRatan Gupta 4888a07d286SRatan Gupta void handleBaseDNPatch(const std::vector<std::string>& baseDNList, 4898a07d286SRatan Gupta const std::shared_ptr<AsyncResp>& asyncResp, 4908a07d286SRatan Gupta const std::string& ldapServerElementName, 4918a07d286SRatan Gupta const std::string& ldapConfigObject) 4928a07d286SRatan Gupta { 4938a07d286SRatan Gupta crow::connections::systemBus->async_method_call( 4948a07d286SRatan Gupta [asyncResp, baseDNList, 4958a07d286SRatan Gupta ldapServerElementName](const boost::system::error_code ec) { 4968a07d286SRatan Gupta if (ec) 4978a07d286SRatan Gupta { 4988a07d286SRatan Gupta BMCWEB_LOG_DEBUG << "Error Occured in Updating the base DN"; 4998a07d286SRatan Gupta messages::internalError(asyncResp->res); 5008a07d286SRatan Gupta return; 5018a07d286SRatan Gupta } 5028a07d286SRatan Gupta auto& serverTypeJson = 5038a07d286SRatan Gupta asyncResp->res.jsonValue[ldapServerElementName]; 5048a07d286SRatan Gupta auto& searchSettingsJson = 5058a07d286SRatan Gupta serverTypeJson["LDAPService"]["SearchSettings"]; 5068a07d286SRatan Gupta std::vector<std::string> modifiedBaseDNList = { 5078a07d286SRatan Gupta baseDNList.front()}; 5088a07d286SRatan Gupta searchSettingsJson["BaseDistinguishedNames"] = 5098a07d286SRatan Gupta modifiedBaseDNList; 5108a07d286SRatan Gupta if (baseDNList.size() > 1) 5118a07d286SRatan Gupta { 5128a07d286SRatan Gupta messages::propertyValueModified(asyncResp->res, 5138a07d286SRatan Gupta "BaseDistinguishedNames", 5148a07d286SRatan Gupta baseDNList.front()); 5158a07d286SRatan Gupta } 5168a07d286SRatan Gupta BMCWEB_LOG_DEBUG << "Updated the base DN"; 5178a07d286SRatan Gupta }, 5188a07d286SRatan Gupta ldapDbusService, ldapConfigObject, propertyInterface, "Set", 5198a07d286SRatan Gupta ldapConfigInterface, "LDAPBaseDN", 5208a07d286SRatan Gupta std::variant<std::string>(baseDNList.front())); 5218a07d286SRatan Gupta } 5228a07d286SRatan Gupta /** 5238a07d286SRatan Gupta * @brief updates the LDAP user name attribute and updates the 5248a07d286SRatan Gupta json response with the new value. 5258a07d286SRatan Gupta * @param userNameAttribute attribute to be updated. 5268a07d286SRatan Gupta * @param asyncResp pointer to the JSON response 5278a07d286SRatan Gupta * @param ldapServerElementName Type of LDAP 5288a07d286SRatan Gupta server(openLDAP/ActiveDirectory) 5298a07d286SRatan Gupta */ 5308a07d286SRatan Gupta 5318a07d286SRatan Gupta void handleUserNameAttrPatch(const std::string& userNameAttribute, 5328a07d286SRatan Gupta const std::shared_ptr<AsyncResp>& asyncResp, 5338a07d286SRatan Gupta const std::string& ldapServerElementName, 5348a07d286SRatan Gupta const std::string& ldapConfigObject) 5358a07d286SRatan Gupta { 5368a07d286SRatan Gupta crow::connections::systemBus->async_method_call( 5378a07d286SRatan Gupta [asyncResp, userNameAttribute, 5388a07d286SRatan Gupta ldapServerElementName](const boost::system::error_code ec) { 5398a07d286SRatan Gupta if (ec) 5408a07d286SRatan Gupta { 5418a07d286SRatan Gupta BMCWEB_LOG_DEBUG << "Error Occured in Updating the " 5428a07d286SRatan Gupta "username attribute"; 5438a07d286SRatan Gupta messages::internalError(asyncResp->res); 5448a07d286SRatan Gupta return; 5458a07d286SRatan Gupta } 5468a07d286SRatan Gupta auto& serverTypeJson = 5478a07d286SRatan Gupta asyncResp->res.jsonValue[ldapServerElementName]; 5488a07d286SRatan Gupta auto& searchSettingsJson = 5498a07d286SRatan Gupta serverTypeJson["LDAPService"]["SearchSettings"]; 5508a07d286SRatan Gupta searchSettingsJson["UsernameAttribute"] = userNameAttribute; 5518a07d286SRatan Gupta BMCWEB_LOG_DEBUG << "Updated the user name attr."; 5528a07d286SRatan Gupta }, 5538a07d286SRatan Gupta ldapDbusService, ldapConfigObject, propertyInterface, "Set", 5548a07d286SRatan Gupta ldapConfigInterface, "UserNameAttribute", 5558a07d286SRatan Gupta std::variant<std::string>(userNameAttribute)); 5568a07d286SRatan Gupta } 5578a07d286SRatan Gupta /** 5588a07d286SRatan Gupta * @brief updates the LDAP group attribute and updates the 5598a07d286SRatan Gupta json response with the new value. 5608a07d286SRatan Gupta * @param groupsAttribute attribute to be updated. 5618a07d286SRatan Gupta * @param asyncResp pointer to the JSON response 5628a07d286SRatan Gupta * @param ldapServerElementName Type of LDAP 5638a07d286SRatan Gupta server(openLDAP/ActiveDirectory) 5648a07d286SRatan Gupta */ 5658a07d286SRatan Gupta 5668a07d286SRatan Gupta void handleGroupNameAttrPatch(const std::string& groupsAttribute, 5678a07d286SRatan Gupta const std::shared_ptr<AsyncResp>& asyncResp, 5688a07d286SRatan Gupta const std::string& ldapServerElementName, 5698a07d286SRatan Gupta const std::string& ldapConfigObject) 5708a07d286SRatan Gupta { 5718a07d286SRatan Gupta crow::connections::systemBus->async_method_call( 5728a07d286SRatan Gupta [asyncResp, groupsAttribute, 5738a07d286SRatan Gupta ldapServerElementName](const boost::system::error_code ec) { 5748a07d286SRatan Gupta if (ec) 5758a07d286SRatan Gupta { 5768a07d286SRatan Gupta BMCWEB_LOG_DEBUG << "Error Occured in Updating the " 5778a07d286SRatan Gupta "groupname attribute"; 5788a07d286SRatan Gupta messages::internalError(asyncResp->res); 5798a07d286SRatan Gupta return; 5808a07d286SRatan Gupta } 5818a07d286SRatan Gupta auto& serverTypeJson = 5828a07d286SRatan Gupta asyncResp->res.jsonValue[ldapServerElementName]; 5838a07d286SRatan Gupta auto& searchSettingsJson = 5848a07d286SRatan Gupta serverTypeJson["LDAPService"]["SearchSettings"]; 5858a07d286SRatan Gupta searchSettingsJson["GroupsAttribute"] = groupsAttribute; 5868a07d286SRatan Gupta BMCWEB_LOG_DEBUG << "Updated the groupname attr"; 5878a07d286SRatan Gupta }, 5888a07d286SRatan Gupta ldapDbusService, ldapConfigObject, propertyInterface, "Set", 5898a07d286SRatan Gupta ldapConfigInterface, "GroupNameAttribute", 5908a07d286SRatan Gupta std::variant<std::string>(groupsAttribute)); 5918a07d286SRatan Gupta } 5928a07d286SRatan Gupta /** 5938a07d286SRatan Gupta * @brief updates the LDAP service enable and updates the 5948a07d286SRatan Gupta json response with the new value. 5958a07d286SRatan Gupta * @param input JSON data. 5968a07d286SRatan Gupta * @param asyncResp pointer to the JSON response 5978a07d286SRatan Gupta * @param ldapServerElementName Type of LDAP 5988a07d286SRatan Gupta server(openLDAP/ActiveDirectory) 5998a07d286SRatan Gupta */ 6008a07d286SRatan Gupta 6018a07d286SRatan Gupta void handleServiceEnablePatch(bool serviceEnabled, 6028a07d286SRatan Gupta const std::shared_ptr<AsyncResp>& asyncResp, 6038a07d286SRatan Gupta const std::string& ldapServerElementName, 6048a07d286SRatan Gupta const std::string& ldapConfigObject) 6058a07d286SRatan Gupta { 6068a07d286SRatan Gupta crow::connections::systemBus->async_method_call( 6078a07d286SRatan Gupta [asyncResp, serviceEnabled, 6088a07d286SRatan Gupta ldapServerElementName](const boost::system::error_code ec) { 6098a07d286SRatan Gupta if (ec) 6108a07d286SRatan Gupta { 6118a07d286SRatan Gupta BMCWEB_LOG_DEBUG 6128a07d286SRatan Gupta << "Error Occured in Updating the service enable"; 6138a07d286SRatan Gupta messages::internalError(asyncResp->res); 6148a07d286SRatan Gupta return; 6158a07d286SRatan Gupta } 6168a07d286SRatan Gupta asyncResp->res 6178a07d286SRatan Gupta .jsonValue[ldapServerElementName]["ServiceEnabled"] = 6188a07d286SRatan Gupta serviceEnabled; 6198a07d286SRatan Gupta BMCWEB_LOG_DEBUG << "Updated Service enable = " 6208a07d286SRatan Gupta << serviceEnabled; 6218a07d286SRatan Gupta }, 6228a07d286SRatan Gupta ldapDbusService, ldapConfigObject, propertyInterface, "Set", 6238a07d286SRatan Gupta ldapEnableInterface, "Enabled", std::variant<bool>(serviceEnabled)); 6248a07d286SRatan Gupta } 6258a07d286SRatan Gupta 6268a07d286SRatan Gupta /** 6278a07d286SRatan Gupta * @brief Get the required values from the given JSON, validates the 6288a07d286SRatan Gupta * value and create the LDAP config object. 6298a07d286SRatan Gupta * @param input JSON data 6308a07d286SRatan Gupta * @param asyncResp pointer to the JSON response 6318a07d286SRatan Gupta * @param serverType Type of LDAP server(openLDAP/ActiveDirectory) 6328a07d286SRatan Gupta */ 6338a07d286SRatan Gupta 6348a07d286SRatan Gupta void handleLDAPPatch(nlohmann::json& input, 6358a07d286SRatan Gupta const std::shared_ptr<AsyncResp>& asyncResp, 6368a07d286SRatan Gupta const crow::Request& req, 6378a07d286SRatan Gupta const std::vector<std::string>& params, 6388a07d286SRatan Gupta const std::string& serverType) 6398a07d286SRatan Gupta { 640eb2bbe56SRatan Gupta std::string dbusObjectPath; 641eb2bbe56SRatan Gupta if (serverType == "ActiveDirectory") 642eb2bbe56SRatan Gupta { 643eb2bbe56SRatan Gupta dbusObjectPath = ADConfigObject; 644eb2bbe56SRatan Gupta } 645eb2bbe56SRatan Gupta else if (serverType == "LDAP") 646eb2bbe56SRatan Gupta { 647eb2bbe56SRatan Gupta dbusObjectPath = ldapConfigObject; 648eb2bbe56SRatan Gupta } 649eb2bbe56SRatan Gupta 6508a07d286SRatan Gupta std::optional<nlohmann::json> authentication; 6518a07d286SRatan Gupta std::optional<nlohmann::json> ldapService; 6528a07d286SRatan Gupta std::optional<std::string> accountProviderType; 6538a07d286SRatan Gupta std::optional<std::vector<std::string>> serviceAddressList; 6548a07d286SRatan Gupta std::optional<bool> serviceEnabled; 6558a07d286SRatan Gupta std::optional<std::vector<std::string>> baseDNList; 6568a07d286SRatan Gupta std::optional<std::string> userNameAttribute; 6578a07d286SRatan Gupta std::optional<std::string> groupsAttribute; 6588a07d286SRatan Gupta std::optional<std::string> userName; 6598a07d286SRatan Gupta std::optional<std::string> password; 6608a07d286SRatan Gupta 6618a07d286SRatan Gupta if (!json_util::readJson(input, asyncResp->res, "Authentication", 6628a07d286SRatan Gupta authentication, "LDAPService", ldapService, 6638a07d286SRatan Gupta "ServiceAddresses", serviceAddressList, 6648a07d286SRatan Gupta "AccountProviderType", accountProviderType, 6658a07d286SRatan Gupta "ServiceEnabled", serviceEnabled)) 6668a07d286SRatan Gupta { 6678a07d286SRatan Gupta return; 6688a07d286SRatan Gupta } 6698a07d286SRatan Gupta 6708a07d286SRatan Gupta if (authentication) 6718a07d286SRatan Gupta { 6728a07d286SRatan Gupta parseLDAPAuthenticationJson(*authentication, asyncResp, userName, 6738a07d286SRatan Gupta password); 6748a07d286SRatan Gupta } 6758a07d286SRatan Gupta if (ldapService) 6768a07d286SRatan Gupta { 6778a07d286SRatan Gupta parseLDAPServiceJson(*ldapService, asyncResp, baseDNList, 6788a07d286SRatan Gupta userNameAttribute, groupsAttribute); 6798a07d286SRatan Gupta } 6808a07d286SRatan Gupta if (accountProviderType) 6818a07d286SRatan Gupta { 6828a07d286SRatan Gupta messages::propertyNotWritable(asyncResp->res, 6838a07d286SRatan Gupta "AccountProviderType"); 6848a07d286SRatan Gupta } 6858a07d286SRatan Gupta if (serviceAddressList) 6868a07d286SRatan Gupta { 6878a07d286SRatan Gupta if ((*serviceAddressList).size() == 0) 6888a07d286SRatan Gupta { 6898a07d286SRatan Gupta messages::propertyValueNotInList(asyncResp->res, "[]", 6908a07d286SRatan Gupta "ServiceAddress"); 6918a07d286SRatan Gupta return; 6928a07d286SRatan Gupta } 6938a07d286SRatan Gupta } 6948a07d286SRatan Gupta if (baseDNList) 6958a07d286SRatan Gupta { 6968a07d286SRatan Gupta if ((*baseDNList).size() == 0) 6978a07d286SRatan Gupta { 6988a07d286SRatan Gupta messages::propertyValueNotInList(asyncResp->res, "[]", 6998a07d286SRatan Gupta "BaseDistinguishedNames"); 7008a07d286SRatan Gupta return; 7018a07d286SRatan Gupta } 7028a07d286SRatan Gupta } 7038a07d286SRatan Gupta 7048a07d286SRatan Gupta // nothing to update, then return 7058a07d286SRatan Gupta if (!userName && !password && !serviceAddressList && !baseDNList && 7068a07d286SRatan Gupta !userNameAttribute && !groupsAttribute && !serviceEnabled) 7078a07d286SRatan Gupta { 7088a07d286SRatan Gupta return; 7098a07d286SRatan Gupta } 7108a07d286SRatan Gupta 7118a07d286SRatan Gupta // Get the existing resource first then keep modifying 7128a07d286SRatan Gupta // whenever any property gets updated. 713ab828d7cSRatan Gupta getLDAPConfigData(serverType, [this, asyncResp, userName, password, 714ab828d7cSRatan Gupta baseDNList, userNameAttribute, 715ab828d7cSRatan Gupta groupsAttribute, accountProviderType, 716eb2bbe56SRatan Gupta serviceAddressList, serviceEnabled, 717eb2bbe56SRatan Gupta dbusObjectPath]( 718ab828d7cSRatan Gupta bool success, LDAPConfigData confData, 719ab828d7cSRatan Gupta const std::string& serverType) { 7208a07d286SRatan Gupta if (!success) 7218a07d286SRatan Gupta { 7228a07d286SRatan Gupta messages::internalError(asyncResp->res); 7238a07d286SRatan Gupta return; 7248a07d286SRatan Gupta } 725ab828d7cSRatan Gupta parseLDAPConfigData(asyncResp->res.jsonValue, confData, serverType); 7268a07d286SRatan Gupta if (confData.serviceEnabled) 7278a07d286SRatan Gupta { 7288a07d286SRatan Gupta // Disable the service first and update the rest of 7298a07d286SRatan Gupta // the properties. 7308a07d286SRatan Gupta handleServiceEnablePatch(false, asyncResp, serverType, 731eb2bbe56SRatan Gupta dbusObjectPath); 7328a07d286SRatan Gupta } 7338a07d286SRatan Gupta 7348a07d286SRatan Gupta if (serviceAddressList) 7358a07d286SRatan Gupta { 7368a07d286SRatan Gupta handleServiceAddressPatch(*serviceAddressList, asyncResp, 737eb2bbe56SRatan Gupta serverType, dbusObjectPath); 7388a07d286SRatan Gupta } 7398a07d286SRatan Gupta if (userName) 7408a07d286SRatan Gupta { 7418a07d286SRatan Gupta handleUserNamePatch(*userName, asyncResp, serverType, 742eb2bbe56SRatan Gupta dbusObjectPath); 7438a07d286SRatan Gupta } 7448a07d286SRatan Gupta if (password) 7458a07d286SRatan Gupta { 7468a07d286SRatan Gupta handlePasswordPatch(*password, asyncResp, serverType, 747eb2bbe56SRatan Gupta dbusObjectPath); 7488a07d286SRatan Gupta } 7498a07d286SRatan Gupta 7508a07d286SRatan Gupta if (baseDNList) 7518a07d286SRatan Gupta { 7528a07d286SRatan Gupta handleBaseDNPatch(*baseDNList, asyncResp, serverType, 753eb2bbe56SRatan Gupta dbusObjectPath); 7548a07d286SRatan Gupta } 7558a07d286SRatan Gupta if (userNameAttribute) 7568a07d286SRatan Gupta { 7578a07d286SRatan Gupta handleUserNameAttrPatch(*userNameAttribute, asyncResp, 758eb2bbe56SRatan Gupta serverType, dbusObjectPath); 7598a07d286SRatan Gupta } 7608a07d286SRatan Gupta if (groupsAttribute) 7618a07d286SRatan Gupta { 7628a07d286SRatan Gupta handleGroupNameAttrPatch(*groupsAttribute, asyncResp, 763eb2bbe56SRatan Gupta serverType, dbusObjectPath); 7648a07d286SRatan Gupta } 7658a07d286SRatan Gupta if (serviceEnabled) 7668a07d286SRatan Gupta { 7678a07d286SRatan Gupta // if user has given the value as true then enable 7688a07d286SRatan Gupta // the service. if user has given false then no-op 7698a07d286SRatan Gupta // as service is already stopped. 7708a07d286SRatan Gupta if (*serviceEnabled) 7718a07d286SRatan Gupta { 7728a07d286SRatan Gupta handleServiceEnablePatch(*serviceEnabled, asyncResp, 773eb2bbe56SRatan Gupta serverType, dbusObjectPath); 7748a07d286SRatan Gupta } 7758a07d286SRatan Gupta } 7768a07d286SRatan Gupta else 7778a07d286SRatan Gupta { 7788a07d286SRatan Gupta // if user has not given the service enabled value 7798a07d286SRatan Gupta // then revert it to the same state as it was 7808a07d286SRatan Gupta // before. 7818a07d286SRatan Gupta handleServiceEnablePatch(confData.serviceEnabled, asyncResp, 782eb2bbe56SRatan Gupta serverType, dbusObjectPath); 7838a07d286SRatan Gupta } 7848a07d286SRatan Gupta }); 7858a07d286SRatan Gupta } 7868a07d286SRatan Gupta 78755c7b7a2SEd Tanous void doGet(crow::Response& res, const crow::Request& req, 7881abe55efSEd Tanous const std::vector<std::string>& params) override 7891abe55efSEd Tanous { 7903d958bbcSAppaRao Puli auto asyncResp = std::make_shared<AsyncResp>(res); 7913d958bbcSAppaRao Puli res.jsonValue = { 7923d958bbcSAppaRao Puli {"@odata.context", "/redfish/v1/" 7933d958bbcSAppaRao Puli "$metadata#AccountService.AccountService"}, 7943d958bbcSAppaRao Puli {"@odata.id", "/redfish/v1/AccountService"}, 7953d958bbcSAppaRao Puli {"@odata.type", "#AccountService." 796*37cce918SMarri Devender Rao "v1_4_0.AccountService"}, 7973d958bbcSAppaRao Puli {"Id", "AccountService"}, 7983d958bbcSAppaRao Puli {"Name", "Account Service"}, 7993d958bbcSAppaRao Puli {"Description", "Account Service"}, 8003d958bbcSAppaRao Puli {"ServiceEnabled", true}, 801343ff2e1SAppaRao Puli {"MaxPasswordLength", 20}, 8023d958bbcSAppaRao Puli {"Accounts", 8033d958bbcSAppaRao Puli {{"@odata.id", "/redfish/v1/AccountService/Accounts"}}}, 804*37cce918SMarri Devender Rao {"Roles", {{"@odata.id", "/redfish/v1/AccountService/Roles"}}}, 805*37cce918SMarri Devender Rao {"LDAP", 806*37cce918SMarri Devender Rao {{"Certificates", 807*37cce918SMarri Devender Rao {{"@odata.id", 808*37cce918SMarri Devender Rao "/redfish/v1/AccountService/LDAP/Certificates"}}}}}}; 8093d958bbcSAppaRao Puli crow::connections::systemBus->async_method_call( 8103d958bbcSAppaRao Puli [asyncResp]( 8113d958bbcSAppaRao Puli const boost::system::error_code ec, 8123d958bbcSAppaRao Puli const std::vector<std::pair< 813abf2add6SEd Tanous std::string, std::variant<uint32_t, uint16_t, uint8_t>>>& 8143d958bbcSAppaRao Puli propertiesList) { 8153d958bbcSAppaRao Puli if (ec) 8163d958bbcSAppaRao Puli { 8173d958bbcSAppaRao Puli messages::internalError(asyncResp->res); 8183d958bbcSAppaRao Puli return; 8193d958bbcSAppaRao Puli } 8203d958bbcSAppaRao Puli BMCWEB_LOG_DEBUG << "Got " << propertiesList.size() 8213d958bbcSAppaRao Puli << "properties for AccountService"; 8223d958bbcSAppaRao Puli for (const std::pair<std::string, 823abf2add6SEd Tanous std::variant<uint32_t, uint16_t, uint8_t>>& 8243d958bbcSAppaRao Puli property : propertiesList) 8253d958bbcSAppaRao Puli { 8263d958bbcSAppaRao Puli if (property.first == "MinPasswordLength") 8273d958bbcSAppaRao Puli { 8283d958bbcSAppaRao Puli const uint8_t* value = 829abf2add6SEd Tanous std::get_if<uint8_t>(&property.second); 8303d958bbcSAppaRao Puli if (value != nullptr) 8313d958bbcSAppaRao Puli { 8323d958bbcSAppaRao Puli asyncResp->res.jsonValue["MinPasswordLength"] = 8333d958bbcSAppaRao Puli *value; 8343d958bbcSAppaRao Puli } 8353d958bbcSAppaRao Puli } 8363d958bbcSAppaRao Puli if (property.first == "AccountUnlockTimeout") 8373d958bbcSAppaRao Puli { 8383d958bbcSAppaRao Puli const uint32_t* value = 839abf2add6SEd Tanous std::get_if<uint32_t>(&property.second); 8403d958bbcSAppaRao Puli if (value != nullptr) 8413d958bbcSAppaRao Puli { 8423d958bbcSAppaRao Puli asyncResp->res.jsonValue["AccountLockoutDuration"] = 8433d958bbcSAppaRao Puli *value; 8443d958bbcSAppaRao Puli } 8453d958bbcSAppaRao Puli } 8463d958bbcSAppaRao Puli if (property.first == "MaxLoginAttemptBeforeLockout") 8473d958bbcSAppaRao Puli { 8483d958bbcSAppaRao Puli const uint16_t* value = 849abf2add6SEd Tanous std::get_if<uint16_t>(&property.second); 8503d958bbcSAppaRao Puli if (value != nullptr) 8513d958bbcSAppaRao Puli { 8523d958bbcSAppaRao Puli asyncResp->res 8533d958bbcSAppaRao Puli .jsonValue["AccountLockoutThreshold"] = *value; 8543d958bbcSAppaRao Puli } 8553d958bbcSAppaRao Puli } 8563d958bbcSAppaRao Puli } 8573d958bbcSAppaRao Puli }, 8583d958bbcSAppaRao Puli "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user", 8593d958bbcSAppaRao Puli "org.freedesktop.DBus.Properties", "GetAll", 8603d958bbcSAppaRao Puli "xyz.openbmc_project.User.AccountPolicy"); 8616973a582SRatan Gupta 862ab828d7cSRatan Gupta auto callback = [asyncResp](bool success, LDAPConfigData& confData, 863ab828d7cSRatan Gupta const std::string& ldapType) { 864ab828d7cSRatan Gupta parseLDAPConfigData(asyncResp->res.jsonValue, confData, ldapType); 865ab828d7cSRatan Gupta }; 866ab828d7cSRatan Gupta 867ab828d7cSRatan Gupta getLDAPConfigData("LDAP", callback); 868ab828d7cSRatan Gupta getLDAPConfigData("ActiveDirectory", callback); 8693d958bbcSAppaRao Puli } 8706973a582SRatan Gupta 8713d958bbcSAppaRao Puli void doPatch(crow::Response& res, const crow::Request& req, 8723d958bbcSAppaRao Puli const std::vector<std::string>& params) override 8733d958bbcSAppaRao Puli { 8743d958bbcSAppaRao Puli auto asyncResp = std::make_shared<AsyncResp>(res); 8753d958bbcSAppaRao Puli 8763d958bbcSAppaRao Puli std::optional<uint32_t> unlockTimeout; 8773d958bbcSAppaRao Puli std::optional<uint16_t> lockoutThreshold; 87819fb6e71SRatan Gupta std::optional<uint16_t> minPasswordLength; 87919fb6e71SRatan Gupta std::optional<uint16_t> maxPasswordLength; 8808a07d286SRatan Gupta std::optional<nlohmann::json> ldapObject; 881eb2bbe56SRatan Gupta std::optional<nlohmann::json> activeDirectoryObject; 88219fb6e71SRatan Gupta 8833d958bbcSAppaRao Puli if (!json_util::readJson(req, res, "AccountLockoutDuration", 8843d958bbcSAppaRao Puli unlockTimeout, "AccountLockoutThreshold", 88519fb6e71SRatan Gupta lockoutThreshold, "MaxPasswordLength", 88619fb6e71SRatan Gupta maxPasswordLength, "MinPasswordLength", 887eb2bbe56SRatan Gupta minPasswordLength, "LDAP", ldapObject, 888eb2bbe56SRatan Gupta "ActiveDirectory", activeDirectoryObject)) 8893d958bbcSAppaRao Puli { 8903d958bbcSAppaRao Puli return; 8913d958bbcSAppaRao Puli } 89219fb6e71SRatan Gupta 89319fb6e71SRatan Gupta if (minPasswordLength) 89419fb6e71SRatan Gupta { 89519fb6e71SRatan Gupta messages::propertyNotWritable(asyncResp->res, "MinPasswordLength"); 89619fb6e71SRatan Gupta } 89719fb6e71SRatan Gupta 89819fb6e71SRatan Gupta if (maxPasswordLength) 89919fb6e71SRatan Gupta { 90019fb6e71SRatan Gupta messages::propertyNotWritable(asyncResp->res, "MaxPasswordLength"); 90119fb6e71SRatan Gupta } 90219fb6e71SRatan Gupta 9038a07d286SRatan Gupta if (ldapObject) 9048a07d286SRatan Gupta { 9058a07d286SRatan Gupta handleLDAPPatch(*ldapObject, asyncResp, req, params, "LDAP"); 9068a07d286SRatan Gupta } 9078a07d286SRatan Gupta 908eb2bbe56SRatan Gupta if (activeDirectoryObject) 909eb2bbe56SRatan Gupta { 910eb2bbe56SRatan Gupta handleLDAPPatch(*activeDirectoryObject, asyncResp, req, params, 911eb2bbe56SRatan Gupta "ActiveDirectory"); 912eb2bbe56SRatan Gupta } 913eb2bbe56SRatan Gupta 9143d958bbcSAppaRao Puli if (unlockTimeout) 9153d958bbcSAppaRao Puli { 9163d958bbcSAppaRao Puli crow::connections::systemBus->async_method_call( 9173d958bbcSAppaRao Puli [asyncResp](const boost::system::error_code ec) { 9183d958bbcSAppaRao Puli if (ec) 9193d958bbcSAppaRao Puli { 9203d958bbcSAppaRao Puli messages::internalError(asyncResp->res); 9213d958bbcSAppaRao Puli return; 9223d958bbcSAppaRao Puli } 923add6133bSRatan Gupta messages::success(asyncResp->res); 9243d958bbcSAppaRao Puli }, 9253d958bbcSAppaRao Puli "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user", 9263d958bbcSAppaRao Puli "org.freedesktop.DBus.Properties", "Set", 9273d958bbcSAppaRao Puli "xyz.openbmc_project.User.AccountPolicy", 928abf2add6SEd Tanous "AccountUnlockTimeout", std::variant<uint32_t>(*unlockTimeout)); 9293d958bbcSAppaRao Puli } 9303d958bbcSAppaRao Puli if (lockoutThreshold) 9313d958bbcSAppaRao Puli { 9323d958bbcSAppaRao Puli crow::connections::systemBus->async_method_call( 9333d958bbcSAppaRao Puli [asyncResp](const boost::system::error_code ec) { 9343d958bbcSAppaRao Puli if (ec) 9353d958bbcSAppaRao Puli { 9363d958bbcSAppaRao Puli messages::internalError(asyncResp->res); 9373d958bbcSAppaRao Puli return; 9383d958bbcSAppaRao Puli } 939add6133bSRatan Gupta messages::success(asyncResp->res); 9403d958bbcSAppaRao Puli }, 9413d958bbcSAppaRao Puli "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user", 9423d958bbcSAppaRao Puli "org.freedesktop.DBus.Properties", "Set", 9433d958bbcSAppaRao Puli "xyz.openbmc_project.User.AccountPolicy", 9443d958bbcSAppaRao Puli "MaxLoginAttemptBeforeLockout", 945abf2add6SEd Tanous std::variant<uint16_t>(*lockoutThreshold)); 9463d958bbcSAppaRao Puli } 94788d16c9aSLewanczyk, Dawid } 94888d16c9aSLewanczyk, Dawid }; 949f00032dbSTanous 950b9b2e0b2SEd Tanous class AccountsCollection : public Node 951b9b2e0b2SEd Tanous { 952b9b2e0b2SEd Tanous public: 953b9b2e0b2SEd Tanous AccountsCollection(CrowApp& app) : 954b9b2e0b2SEd Tanous Node(app, "/redfish/v1/AccountService/Accounts/") 955b9b2e0b2SEd Tanous { 956b9b2e0b2SEd Tanous entityPrivileges = { 957b9b2e0b2SEd Tanous {boost::beast::http::verb::get, 958b9b2e0b2SEd Tanous {{"ConfigureUsers"}, {"ConfigureManager"}}}, 959b9b2e0b2SEd Tanous {boost::beast::http::verb::head, {{"Login"}}}, 960b9b2e0b2SEd Tanous {boost::beast::http::verb::patch, {{"ConfigureUsers"}}}, 961b9b2e0b2SEd Tanous {boost::beast::http::verb::put, {{"ConfigureUsers"}}}, 962b9b2e0b2SEd Tanous {boost::beast::http::verb::delete_, {{"ConfigureUsers"}}}, 963b9b2e0b2SEd Tanous {boost::beast::http::verb::post, {{"ConfigureUsers"}}}}; 964b9b2e0b2SEd Tanous } 965b9b2e0b2SEd Tanous 966b9b2e0b2SEd Tanous private: 967b9b2e0b2SEd Tanous void doGet(crow::Response& res, const crow::Request& req, 968b9b2e0b2SEd Tanous const std::vector<std::string>& params) override 969b9b2e0b2SEd Tanous { 970b9b2e0b2SEd Tanous auto asyncResp = std::make_shared<AsyncResp>(res); 9710f74e643SEd Tanous res.jsonValue = {{"@odata.context", 9720f74e643SEd Tanous "/redfish/v1/" 9730f74e643SEd Tanous "$metadata#ManagerAccountCollection." 9740f74e643SEd Tanous "ManagerAccountCollection"}, 9750f74e643SEd Tanous {"@odata.id", "/redfish/v1/AccountService/Accounts"}, 9760f74e643SEd Tanous {"@odata.type", "#ManagerAccountCollection." 9770f74e643SEd Tanous "ManagerAccountCollection"}, 9780f74e643SEd Tanous {"Name", "Accounts Collection"}, 9790f74e643SEd Tanous {"Description", "BMC User Accounts"}}; 9800f74e643SEd Tanous 981b9b2e0b2SEd Tanous crow::connections::systemBus->async_method_call( 982b9b2e0b2SEd Tanous [asyncResp](const boost::system::error_code ec, 983b9b2e0b2SEd Tanous const ManagedObjectType& users) { 984b9b2e0b2SEd Tanous if (ec) 985b9b2e0b2SEd Tanous { 986f12894f8SJason M. Bills messages::internalError(asyncResp->res); 987b9b2e0b2SEd Tanous return; 988b9b2e0b2SEd Tanous } 989b9b2e0b2SEd Tanous 990b9b2e0b2SEd Tanous nlohmann::json& memberArray = 991b9b2e0b2SEd Tanous asyncResp->res.jsonValue["Members"]; 992b9b2e0b2SEd Tanous memberArray = nlohmann::json::array(); 993b9b2e0b2SEd Tanous 994b9b2e0b2SEd Tanous asyncResp->res.jsonValue["Members@odata.count"] = users.size(); 995b9b2e0b2SEd Tanous for (auto& user : users) 996b9b2e0b2SEd Tanous { 997b9b2e0b2SEd Tanous const std::string& path = 998b9b2e0b2SEd Tanous static_cast<const std::string&>(user.first); 999b9b2e0b2SEd Tanous std::size_t lastIndex = path.rfind("/"); 1000b9b2e0b2SEd Tanous if (lastIndex == std::string::npos) 1001b9b2e0b2SEd Tanous { 1002b9b2e0b2SEd Tanous lastIndex = 0; 1003b9b2e0b2SEd Tanous } 1004b9b2e0b2SEd Tanous else 1005b9b2e0b2SEd Tanous { 1006b9b2e0b2SEd Tanous lastIndex += 1; 1007b9b2e0b2SEd Tanous } 1008b9b2e0b2SEd Tanous memberArray.push_back( 1009b9b2e0b2SEd Tanous {{"@odata.id", "/redfish/v1/AccountService/Accounts/" + 1010b9b2e0b2SEd Tanous path.substr(lastIndex)}}); 1011b9b2e0b2SEd Tanous } 1012b9b2e0b2SEd Tanous }, 1013b9b2e0b2SEd Tanous "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user", 1014b9b2e0b2SEd Tanous "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 1015b9b2e0b2SEd Tanous } 101604ae99ecSEd Tanous void doPost(crow::Response& res, const crow::Request& req, 101704ae99ecSEd Tanous const std::vector<std::string>& params) override 101804ae99ecSEd Tanous { 101904ae99ecSEd Tanous auto asyncResp = std::make_shared<AsyncResp>(res); 102004ae99ecSEd Tanous 10219712f8acSEd Tanous std::string username; 10229712f8acSEd Tanous std::string password; 1023a24526dcSEd Tanous std::optional<std::string> roleId("User"); 1024a24526dcSEd Tanous std::optional<bool> enabled = true; 10259712f8acSEd Tanous if (!json_util::readJson(req, res, "UserName", username, "Password", 10269712f8acSEd Tanous password, "RoleId", roleId, "Enabled", 10279712f8acSEd Tanous enabled)) 102804ae99ecSEd Tanous { 102904ae99ecSEd Tanous return; 103004ae99ecSEd Tanous } 103104ae99ecSEd Tanous 103284e12cb7SAppaRao Puli std::string priv = getRoleIdFromPrivilege(*roleId); 103384e12cb7SAppaRao Puli if (priv.empty()) 103404ae99ecSEd Tanous { 1035f12894f8SJason M. Bills messages::propertyValueNotInList(asyncResp->res, *roleId, "RoleId"); 103604ae99ecSEd Tanous return; 103704ae99ecSEd Tanous } 10389712f8acSEd Tanous roleId = priv; 103904ae99ecSEd Tanous 104004ae99ecSEd Tanous crow::connections::systemBus->async_method_call( 10419712f8acSEd Tanous [asyncResp, username, password{std::move(password)}]( 104204ae99ecSEd Tanous const boost::system::error_code ec) { 104304ae99ecSEd Tanous if (ec) 104404ae99ecSEd Tanous { 104504ae99ecSEd Tanous messages::resourceAlreadyExists( 1046f12894f8SJason M. Bills asyncResp->res, "#ManagerAccount.v1_0_3.ManagerAccount", 1047f12894f8SJason M. Bills "UserName", username); 104804ae99ecSEd Tanous return; 104904ae99ecSEd Tanous } 105004ae99ecSEd Tanous 105104ae99ecSEd Tanous if (!pamUpdatePassword(username, password)) 105204ae99ecSEd Tanous { 105304ae99ecSEd Tanous // At this point we have a user that's been created, but the 105404ae99ecSEd Tanous // password set failed. Something is wrong, so delete the 105504ae99ecSEd Tanous // user that we've already created 105604ae99ecSEd Tanous crow::connections::systemBus->async_method_call( 105704ae99ecSEd Tanous [asyncResp](const boost::system::error_code ec) { 105804ae99ecSEd Tanous if (ec) 105904ae99ecSEd Tanous { 1060f12894f8SJason M. Bills messages::internalError(asyncResp->res); 106104ae99ecSEd Tanous return; 106204ae99ecSEd Tanous } 106304ae99ecSEd Tanous 1064f12894f8SJason M. Bills messages::invalidObject(asyncResp->res, "Password"); 106504ae99ecSEd Tanous }, 106604ae99ecSEd Tanous "xyz.openbmc_project.User.Manager", 106704ae99ecSEd Tanous "/xyz/openbmc_project/user/" + username, 106804ae99ecSEd Tanous "xyz.openbmc_project.Object.Delete", "Delete"); 106904ae99ecSEd Tanous 107004ae99ecSEd Tanous BMCWEB_LOG_ERROR << "pamUpdatePassword Failed"; 107104ae99ecSEd Tanous return; 107204ae99ecSEd Tanous } 107304ae99ecSEd Tanous 1074f12894f8SJason M. Bills messages::created(asyncResp->res); 107504ae99ecSEd Tanous asyncResp->res.addHeader( 107604ae99ecSEd Tanous "Location", 107704ae99ecSEd Tanous "/redfish/v1/AccountService/Accounts/" + username); 107804ae99ecSEd Tanous }, 107904ae99ecSEd Tanous "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user", 10809712f8acSEd Tanous "xyz.openbmc_project.User.Manager", "CreateUser", username, 108104ae99ecSEd Tanous std::array<const char*, 4>{"ipmi", "redfish", "ssh", "web"}, 10829712f8acSEd Tanous *roleId, *enabled); 108304ae99ecSEd Tanous } 1084b9b2e0b2SEd Tanous }; 1085b9b2e0b2SEd Tanous 1086b9b2e0b2SEd Tanous class ManagerAccount : public Node 1087b9b2e0b2SEd Tanous { 1088b9b2e0b2SEd Tanous public: 1089b9b2e0b2SEd Tanous ManagerAccount(CrowApp& app) : 1090b9b2e0b2SEd Tanous Node(app, "/redfish/v1/AccountService/Accounts/<str>/", std::string()) 1091b9b2e0b2SEd Tanous { 1092b9b2e0b2SEd Tanous entityPrivileges = { 1093b9b2e0b2SEd Tanous {boost::beast::http::verb::get, 1094b9b2e0b2SEd Tanous {{"ConfigureUsers"}, {"ConfigureManager"}, {"ConfigureSelf"}}}, 1095b9b2e0b2SEd Tanous {boost::beast::http::verb::head, {{"Login"}}}, 1096b9b2e0b2SEd Tanous {boost::beast::http::verb::patch, {{"ConfigureUsers"}}}, 1097b9b2e0b2SEd Tanous {boost::beast::http::verb::put, {{"ConfigureUsers"}}}, 1098b9b2e0b2SEd Tanous {boost::beast::http::verb::delete_, {{"ConfigureUsers"}}}, 1099b9b2e0b2SEd Tanous {boost::beast::http::verb::post, {{"ConfigureUsers"}}}}; 1100b9b2e0b2SEd Tanous } 1101b9b2e0b2SEd Tanous 1102b9b2e0b2SEd Tanous private: 1103b9b2e0b2SEd Tanous void doGet(crow::Response& res, const crow::Request& req, 1104b9b2e0b2SEd Tanous const std::vector<std::string>& params) override 1105b9b2e0b2SEd Tanous { 11060f74e643SEd Tanous res.jsonValue = { 11070f74e643SEd Tanous {"@odata.context", 11080f74e643SEd Tanous "/redfish/v1/$metadata#ManagerAccount.ManagerAccount"}, 11090f74e643SEd Tanous {"@odata.type", "#ManagerAccount.v1_0_3.ManagerAccount"}, 11100f74e643SEd Tanous {"Name", "User Account"}, 11110f74e643SEd Tanous {"Description", "User Account"}, 11120f74e643SEd Tanous {"Password", nullptr}, 111384e12cb7SAppaRao Puli {"RoleId", "Administrator"}}; 11140f74e643SEd Tanous 1115b9b2e0b2SEd Tanous auto asyncResp = std::make_shared<AsyncResp>(res); 1116b9b2e0b2SEd Tanous 1117b9b2e0b2SEd Tanous if (params.size() != 1) 1118b9b2e0b2SEd Tanous { 1119f12894f8SJason M. Bills messages::internalError(asyncResp->res); 1120b9b2e0b2SEd Tanous return; 1121b9b2e0b2SEd Tanous } 1122b9b2e0b2SEd Tanous 1123b9b2e0b2SEd Tanous crow::connections::systemBus->async_method_call( 1124b9b2e0b2SEd Tanous [asyncResp, accountName{std::string(params[0])}]( 1125b9b2e0b2SEd Tanous const boost::system::error_code ec, 1126b9b2e0b2SEd Tanous const ManagedObjectType& users) { 1127b9b2e0b2SEd Tanous if (ec) 1128b9b2e0b2SEd Tanous { 1129f12894f8SJason M. Bills messages::internalError(asyncResp->res); 1130b9b2e0b2SEd Tanous return; 1131b9b2e0b2SEd Tanous } 113284e12cb7SAppaRao Puli auto userIt = users.begin(); 1133b9b2e0b2SEd Tanous 113484e12cb7SAppaRao Puli for (; userIt != users.end(); userIt++) 1135b9b2e0b2SEd Tanous { 113684e12cb7SAppaRao Puli if (boost::ends_with(userIt->first.str, "/" + accountName)) 1137b9b2e0b2SEd Tanous { 113884e12cb7SAppaRao Puli break; 1139b9b2e0b2SEd Tanous } 1140b9b2e0b2SEd Tanous } 114184e12cb7SAppaRao Puli if (userIt == users.end()) 1142b9b2e0b2SEd Tanous { 114384e12cb7SAppaRao Puli messages::resourceNotFound(asyncResp->res, "ManagerAccount", 114484e12cb7SAppaRao Puli accountName); 114584e12cb7SAppaRao Puli return; 114684e12cb7SAppaRao Puli } 114784e12cb7SAppaRao Puli for (const auto& interface : userIt->second) 114865b0dc32SEd Tanous { 114965b0dc32SEd Tanous if (interface.first == 115065b0dc32SEd Tanous "xyz.openbmc_project.User.Attributes") 115165b0dc32SEd Tanous { 115265b0dc32SEd Tanous for (const auto& property : interface.second) 115365b0dc32SEd Tanous { 115465b0dc32SEd Tanous if (property.first == "UserEnabled") 115565b0dc32SEd Tanous { 115665b0dc32SEd Tanous const bool* userEnabled = 1157abf2add6SEd Tanous std::get_if<bool>(&property.second); 115865b0dc32SEd Tanous if (userEnabled == nullptr) 115965b0dc32SEd Tanous { 116065b0dc32SEd Tanous BMCWEB_LOG_ERROR 116165b0dc32SEd Tanous << "UserEnabled wasn't a bool"; 116284e12cb7SAppaRao Puli messages::internalError(asyncResp->res); 116384e12cb7SAppaRao Puli return; 116465b0dc32SEd Tanous } 116565b0dc32SEd Tanous asyncResp->res.jsonValue["Enabled"] = 116665b0dc32SEd Tanous *userEnabled; 116765b0dc32SEd Tanous } 116865b0dc32SEd Tanous else if (property.first == 116965b0dc32SEd Tanous "UserLockedForFailedAttempt") 117065b0dc32SEd Tanous { 117165b0dc32SEd Tanous const bool* userLocked = 1172abf2add6SEd Tanous std::get_if<bool>(&property.second); 117365b0dc32SEd Tanous if (userLocked == nullptr) 117465b0dc32SEd Tanous { 117584e12cb7SAppaRao Puli BMCWEB_LOG_ERROR << "UserLockedForF" 117684e12cb7SAppaRao Puli "ailedAttempt " 117784e12cb7SAppaRao Puli "wasn't a bool"; 117884e12cb7SAppaRao Puli messages::internalError(asyncResp->res); 117984e12cb7SAppaRao Puli return; 118065b0dc32SEd Tanous } 118165b0dc32SEd Tanous asyncResp->res.jsonValue["Locked"] = 118265b0dc32SEd Tanous *userLocked; 118324c8542dSRatan Gupta asyncResp->res.jsonValue 118424c8542dSRatan Gupta ["Locked@Redfish.AllowableValues"] = { 11854d64ce34SGunnar Mills "false"}; 118665b0dc32SEd Tanous } 118784e12cb7SAppaRao Puli else if (property.first == "UserPrivilege") 118884e12cb7SAppaRao Puli { 118984e12cb7SAppaRao Puli const std::string* userRolePtr = 1190abf2add6SEd Tanous std::get_if<std::string>(&property.second); 119184e12cb7SAppaRao Puli if (userRolePtr == nullptr) 119284e12cb7SAppaRao Puli { 119384e12cb7SAppaRao Puli BMCWEB_LOG_ERROR 119484e12cb7SAppaRao Puli << "UserPrivilege wasn't a " 119584e12cb7SAppaRao Puli "string"; 119684e12cb7SAppaRao Puli messages::internalError(asyncResp->res); 119784e12cb7SAppaRao Puli return; 119884e12cb7SAppaRao Puli } 119984e12cb7SAppaRao Puli std::string priv = 120084e12cb7SAppaRao Puli getPrivilegeFromRoleId(*userRolePtr); 120184e12cb7SAppaRao Puli if (priv.empty()) 120284e12cb7SAppaRao Puli { 120384e12cb7SAppaRao Puli BMCWEB_LOG_ERROR << "Invalid user role"; 120484e12cb7SAppaRao Puli messages::internalError(asyncResp->res); 120584e12cb7SAppaRao Puli return; 120684e12cb7SAppaRao Puli } 120784e12cb7SAppaRao Puli asyncResp->res.jsonValue["RoleId"] = priv; 120884e12cb7SAppaRao Puli 120984e12cb7SAppaRao Puli asyncResp->res.jsonValue["Links"]["Role"] = { 121084e12cb7SAppaRao Puli {"@odata.id", "/redfish/v1/AccountService/" 121184e12cb7SAppaRao Puli "Roles/" + 121284e12cb7SAppaRao Puli priv}}; 121384e12cb7SAppaRao Puli } 121465b0dc32SEd Tanous } 121565b0dc32SEd Tanous } 121665b0dc32SEd Tanous } 121765b0dc32SEd Tanous 1218b9b2e0b2SEd Tanous asyncResp->res.jsonValue["@odata.id"] = 121984e12cb7SAppaRao Puli "/redfish/v1/AccountService/Accounts/" + accountName; 1220b9b2e0b2SEd Tanous asyncResp->res.jsonValue["Id"] = accountName; 1221b9b2e0b2SEd Tanous asyncResp->res.jsonValue["UserName"] = accountName; 1222b9b2e0b2SEd Tanous }, 1223b9b2e0b2SEd Tanous "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user", 1224b9b2e0b2SEd Tanous "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 1225b9b2e0b2SEd Tanous } 1226a840879dSEd Tanous 1227a840879dSEd Tanous void doPatch(crow::Response& res, const crow::Request& req, 1228a840879dSEd Tanous const std::vector<std::string>& params) override 1229a840879dSEd Tanous { 1230a840879dSEd Tanous auto asyncResp = std::make_shared<AsyncResp>(res); 1231a840879dSEd Tanous if (params.size() != 1) 1232a840879dSEd Tanous { 1233f12894f8SJason M. Bills messages::internalError(asyncResp->res); 1234a840879dSEd Tanous return; 1235a840879dSEd Tanous } 1236a840879dSEd Tanous 1237a24526dcSEd Tanous std::optional<std::string> newUserName; 1238a24526dcSEd Tanous std::optional<std::string> password; 1239a24526dcSEd Tanous std::optional<bool> enabled; 1240a24526dcSEd Tanous std::optional<std::string> roleId; 124124c8542dSRatan Gupta std::optional<bool> locked; 124284e12cb7SAppaRao Puli if (!json_util::readJson(req, res, "UserName", newUserName, "Password", 124324c8542dSRatan Gupta password, "RoleId", roleId, "Enabled", enabled, 124424c8542dSRatan Gupta "Locked", locked)) 1245a840879dSEd Tanous { 1246a840879dSEd Tanous return; 1247a840879dSEd Tanous } 1248a840879dSEd Tanous 124984e12cb7SAppaRao Puli const std::string& username = params[0]; 125084e12cb7SAppaRao Puli 125184e12cb7SAppaRao Puli if (!newUserName) 1252a840879dSEd Tanous { 125384e12cb7SAppaRao Puli // If the username isn't being updated, we can update the properties 125484e12cb7SAppaRao Puli // directly 125524c8542dSRatan Gupta updateUserProperties(asyncResp, username, password, enabled, roleId, 125624c8542dSRatan Gupta locked); 125784e12cb7SAppaRao Puli return; 125884e12cb7SAppaRao Puli } 125984e12cb7SAppaRao Puli else 126084e12cb7SAppaRao Puli { 126184e12cb7SAppaRao Puli crow::connections::systemBus->async_method_call( 126284e12cb7SAppaRao Puli [this, asyncResp, username, password(std::move(password)), 126384e12cb7SAppaRao Puli roleId(std::move(roleId)), enabled(std::move(enabled)), 126424c8542dSRatan Gupta newUser{std::string(*newUserName)}, locked(std::move(locked))]( 126584e12cb7SAppaRao Puli const boost::system::error_code ec) { 126684e12cb7SAppaRao Puli if (ec) 126784e12cb7SAppaRao Puli { 126884e12cb7SAppaRao Puli BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec; 1269a840879dSEd Tanous messages::resourceNotFound( 127084e12cb7SAppaRao Puli asyncResp->res, 127184e12cb7SAppaRao Puli "#ManagerAccount.v1_0_3.ManagerAccount", username); 1272a840879dSEd Tanous return; 1273a840879dSEd Tanous } 1274a840879dSEd Tanous 127584e12cb7SAppaRao Puli updateUserProperties(asyncResp, newUser, password, enabled, 127624c8542dSRatan Gupta roleId, locked); 127784e12cb7SAppaRao Puli }, 127884e12cb7SAppaRao Puli "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user", 127984e12cb7SAppaRao Puli "xyz.openbmc_project.User.Manager", "RenameUser", username, 128084e12cb7SAppaRao Puli *newUserName); 128184e12cb7SAppaRao Puli } 128284e12cb7SAppaRao Puli } 128384e12cb7SAppaRao Puli 128484e12cb7SAppaRao Puli void updateUserProperties(std::shared_ptr<AsyncResp> asyncResp, 128584e12cb7SAppaRao Puli const std::string& username, 1286a24526dcSEd Tanous std::optional<std::string> password, 1287a24526dcSEd Tanous std::optional<bool> enabled, 128824c8542dSRatan Gupta std::optional<std::string> roleId, 128924c8542dSRatan Gupta std::optional<bool> locked) 129084e12cb7SAppaRao Puli { 12919712f8acSEd Tanous if (password) 1292a840879dSEd Tanous { 12939712f8acSEd Tanous if (!pamUpdatePassword(username, *password)) 1294a840879dSEd Tanous { 1295a840879dSEd Tanous BMCWEB_LOG_ERROR << "pamUpdatePassword Failed"; 1296f12894f8SJason M. Bills messages::internalError(asyncResp->res); 1297a840879dSEd Tanous return; 1298a840879dSEd Tanous } 1299a840879dSEd Tanous } 1300a840879dSEd Tanous 130124c8542dSRatan Gupta std::string dbusObjectPath = "/xyz/openbmc_project/user/" + username; 130224c8542dSRatan Gupta dbus::utility::escapePathForDbus(dbusObjectPath); 130324c8542dSRatan Gupta 130422c33710SRatan Gupta dbus::utility::checkDbusPathExists( 130524c8542dSRatan Gupta dbusObjectPath, 130624c8542dSRatan Gupta [dbusObjectPath(std::move(dbusObjectPath)), username, 130724c8542dSRatan Gupta password(std::move(password)), roleId(std::move(roleId)), 130824c8542dSRatan Gupta enabled(std::move(enabled)), locked(std::move(locked)), 130924c8542dSRatan Gupta asyncResp{std::move(asyncResp)}](int rc) { 131024c8542dSRatan Gupta if (!rc) 131124c8542dSRatan Gupta { 131224c8542dSRatan Gupta messages::invalidObject(asyncResp->res, username.c_str()); 131324c8542dSRatan Gupta return; 131424c8542dSRatan Gupta } 13159712f8acSEd Tanous if (enabled) 1316a840879dSEd Tanous { 1317a840879dSEd Tanous crow::connections::systemBus->async_method_call( 1318a840879dSEd Tanous [asyncResp](const boost::system::error_code ec) { 1319a840879dSEd Tanous if (ec) 1320a840879dSEd Tanous { 132124c8542dSRatan Gupta BMCWEB_LOG_ERROR << "D-Bus responses error: " 132224c8542dSRatan Gupta << ec; 1323f12894f8SJason M. Bills messages::internalError(asyncResp->res); 1324a840879dSEd Tanous return; 1325a840879dSEd Tanous } 132684e12cb7SAppaRao Puli messages::success(asyncResp->res); 132784e12cb7SAppaRao Puli return; 132884e12cb7SAppaRao Puli }, 132984e12cb7SAppaRao Puli "xyz.openbmc_project.User.Manager", 133024c8542dSRatan Gupta dbusObjectPath.c_str(), 133184e12cb7SAppaRao Puli "org.freedesktop.DBus.Properties", "Set", 133284e12cb7SAppaRao Puli "xyz.openbmc_project.User.Attributes", "UserEnabled", 1333abf2add6SEd Tanous std::variant<bool>{*enabled}); 133484e12cb7SAppaRao Puli } 133584e12cb7SAppaRao Puli 133684e12cb7SAppaRao Puli if (roleId) 133784e12cb7SAppaRao Puli { 133884e12cb7SAppaRao Puli std::string priv = getRoleIdFromPrivilege(*roleId); 133984e12cb7SAppaRao Puli if (priv.empty()) 134084e12cb7SAppaRao Puli { 134124c8542dSRatan Gupta messages::propertyValueNotInList(asyncResp->res, 134224c8542dSRatan Gupta *roleId, "RoleId"); 134384e12cb7SAppaRao Puli return; 134484e12cb7SAppaRao Puli } 134584e12cb7SAppaRao Puli 134684e12cb7SAppaRao Puli crow::connections::systemBus->async_method_call( 134784e12cb7SAppaRao Puli [asyncResp](const boost::system::error_code ec) { 134884e12cb7SAppaRao Puli if (ec) 134984e12cb7SAppaRao Puli { 135024c8542dSRatan Gupta BMCWEB_LOG_ERROR << "D-Bus responses error: " 135124c8542dSRatan Gupta << ec; 135284e12cb7SAppaRao Puli messages::internalError(asyncResp->res); 135384e12cb7SAppaRao Puli return; 135484e12cb7SAppaRao Puli } 1355f12894f8SJason M. Bills messages::success(asyncResp->res); 1356a840879dSEd Tanous }, 1357a840879dSEd Tanous "xyz.openbmc_project.User.Manager", 135824c8542dSRatan Gupta dbusObjectPath.c_str(), 1359a840879dSEd Tanous "org.freedesktop.DBus.Properties", "Set", 136084e12cb7SAppaRao Puli "xyz.openbmc_project.User.Attributes", "UserPrivilege", 1361abf2add6SEd Tanous std::variant<std::string>{priv}); 1362a840879dSEd Tanous } 136324c8542dSRatan Gupta 136424c8542dSRatan Gupta if (locked) 136524c8542dSRatan Gupta { 136624c8542dSRatan Gupta // admin can unlock the account which is locked by 136724c8542dSRatan Gupta // successive authentication failures but admin should not 136824c8542dSRatan Gupta // be allowed to lock an account. 136924c8542dSRatan Gupta if (*locked) 137024c8542dSRatan Gupta { 137124c8542dSRatan Gupta messages::propertyValueNotInList(asyncResp->res, "true", 137224c8542dSRatan Gupta "Locked"); 137324c8542dSRatan Gupta return; 137424c8542dSRatan Gupta } 137524c8542dSRatan Gupta 137624c8542dSRatan Gupta crow::connections::systemBus->async_method_call( 137724c8542dSRatan Gupta [asyncResp](const boost::system::error_code ec) { 137824c8542dSRatan Gupta if (ec) 137924c8542dSRatan Gupta { 138024c8542dSRatan Gupta BMCWEB_LOG_ERROR << "D-Bus responses error: " 138124c8542dSRatan Gupta << ec; 138224c8542dSRatan Gupta messages::internalError(asyncResp->res); 138324c8542dSRatan Gupta return; 138424c8542dSRatan Gupta } 138524c8542dSRatan Gupta messages::success(asyncResp->res); 138624c8542dSRatan Gupta return; 138724c8542dSRatan Gupta }, 138824c8542dSRatan Gupta "xyz.openbmc_project.User.Manager", 138924c8542dSRatan Gupta dbusObjectPath.c_str(), 139024c8542dSRatan Gupta "org.freedesktop.DBus.Properties", "Set", 139124c8542dSRatan Gupta "xyz.openbmc_project.User.Attributes", 139224c8542dSRatan Gupta "UserLockedForFailedAttempt", 139324c8542dSRatan Gupta sdbusplus::message::variant<bool>{*locked}); 139424c8542dSRatan Gupta } 139524c8542dSRatan Gupta }); 1396a840879dSEd Tanous } 139706e086d9SEd Tanous 139806e086d9SEd Tanous void doDelete(crow::Response& res, const crow::Request& req, 139906e086d9SEd Tanous const std::vector<std::string>& params) override 140006e086d9SEd Tanous { 140106e086d9SEd Tanous auto asyncResp = std::make_shared<AsyncResp>(res); 140206e086d9SEd Tanous 140306e086d9SEd Tanous if (params.size() != 1) 140406e086d9SEd Tanous { 1405f12894f8SJason M. Bills messages::internalError(asyncResp->res); 140606e086d9SEd Tanous return; 140706e086d9SEd Tanous } 140806e086d9SEd Tanous 140906e086d9SEd Tanous const std::string userPath = "/xyz/openbmc_project/user/" + params[0]; 141006e086d9SEd Tanous 141106e086d9SEd Tanous crow::connections::systemBus->async_method_call( 141206e086d9SEd Tanous [asyncResp, username{std::move(params[0])}]( 141306e086d9SEd Tanous const boost::system::error_code ec) { 141406e086d9SEd Tanous if (ec) 141506e086d9SEd Tanous { 141606e086d9SEd Tanous messages::resourceNotFound( 1417f12894f8SJason M. Bills asyncResp->res, "#ManagerAccount.v1_0_3.ManagerAccount", 1418f12894f8SJason M. Bills username); 141906e086d9SEd Tanous return; 142006e086d9SEd Tanous } 142106e086d9SEd Tanous 1422f12894f8SJason M. Bills messages::accountRemoved(asyncResp->res); 142306e086d9SEd Tanous }, 142406e086d9SEd Tanous "xyz.openbmc_project.User.Manager", userPath, 142506e086d9SEd Tanous "xyz.openbmc_project.Object.Delete", "Delete"); 142606e086d9SEd Tanous } 142784e12cb7SAppaRao Puli }; 142888d16c9aSLewanczyk, Dawid 142988d16c9aSLewanczyk, Dawid } // namespace redfish 1430