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"; 306973a582SRatan Gupta constexpr const char* ldapRootObject = "/xyz/openbmc_project/user/ldap"; 316973a582SRatan Gupta constexpr const char* ldapDbusService = "xyz.openbmc_project.Ldap.Config"; 326973a582SRatan Gupta constexpr const char* ldapConfigInterface = 336973a582SRatan Gupta "xyz.openbmc_project.User.Ldap.Config"; 346973a582SRatan Gupta constexpr const char* ldapCreateInterface = 356973a582SRatan Gupta "xyz.openbmc_project.User.Ldap.Create"; 366973a582SRatan Gupta constexpr const char* ldapEnableInterface = "xyz.openbmc_project.Object.Enable"; 376973a582SRatan Gupta constexpr const char* dbusObjManagerIntf = "org.freedesktop.DBus.ObjectManager"; 386973a582SRatan Gupta constexpr const char* propertyInterface = "org.freedesktop.DBus.Properties"; 396973a582SRatan Gupta constexpr const char* mapperBusName = "xyz.openbmc_project.ObjectMapper"; 406973a582SRatan Gupta constexpr const char* mapperObjectPath = "/xyz/openbmc_project/object_mapper"; 416973a582SRatan Gupta constexpr const char* mapperIntf = "xyz.openbmc_project.ObjectMapper"; 426973a582SRatan Gupta 436973a582SRatan Gupta struct LDAPConfigData 446973a582SRatan Gupta { 456973a582SRatan Gupta std::string uri{}; 466973a582SRatan Gupta std::string bindDN{}; 476973a582SRatan Gupta std::string baseDN{}; 486973a582SRatan Gupta std::string searchScope{}; 496973a582SRatan Gupta std::string serverType{}; 506973a582SRatan Gupta bool serviceEnabled = false; 516973a582SRatan Gupta std::string userNameAttribute{}; 526973a582SRatan Gupta std::string groupAttribute{}; 536973a582SRatan Gupta }; 546973a582SRatan 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>>>>>; 606973a582SRatan Gupta using GetObjectType = 616973a582SRatan 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 1046973a582SRatan Gupta void parseLDAPConfigData(nlohmann::json& json_response, 1056973a582SRatan Gupta const LDAPConfigData& confData) 1066973a582SRatan Gupta { 1076973a582SRatan Gupta std::string service = "LDAPService"; 1086973a582SRatan Gupta json_response["LDAP"] = { 1096973a582SRatan Gupta {"AccountProviderType", service}, 1106973a582SRatan Gupta {"AccountProviderType@Redfish.AllowableValues", 1116973a582SRatan Gupta nlohmann::json::array({service})}, 1126973a582SRatan Gupta {"ServiceEnabled", confData.serviceEnabled}, 1136973a582SRatan Gupta {"ServiceAddresses", nlohmann::json::array({confData.uri})}, 1146973a582SRatan Gupta {"Authentication", 1156973a582SRatan Gupta {{"AuthenticationType", "UsernameAndPassword"}, 1166973a582SRatan Gupta {"AuthenticationType@Redfish.AllowableValues", 1176973a582SRatan Gupta nlohmann::json::array({"UsernameAndPassword"})}, 1186973a582SRatan Gupta {"Username", confData.bindDN}, 1196973a582SRatan Gupta {"Password", nullptr}}}, 1206973a582SRatan Gupta {"LDAPService", 1216973a582SRatan Gupta {{"SearchSettings", 1226973a582SRatan Gupta {{"BaseDistinguishedNames", 1236973a582SRatan Gupta nlohmann::json::array({confData.baseDN})}, 1246973a582SRatan Gupta {"UsernameAttribute", confData.userNameAttribute}, 1256973a582SRatan Gupta {"GroupsAttribute", confData.groupAttribute}}}}}, 1266973a582SRatan Gupta }; 1276973a582SRatan Gupta } 1286973a582SRatan Gupta 1296973a582SRatan Gupta /** 1306973a582SRatan Gupta * Function that retrieves all properties for LDAP config object 1316973a582SRatan Gupta * into JSON 1326973a582SRatan Gupta */ 1336973a582SRatan Gupta template <typename CallbackFunc> 1346973a582SRatan Gupta inline void getLDAPConfigData(const std::string& ldapType, 1356973a582SRatan Gupta CallbackFunc&& callback) 1366973a582SRatan Gupta { 1376973a582SRatan Gupta auto getConfig = [callback, 1386973a582SRatan Gupta ldapType](const boost::system::error_code error_code, 1396973a582SRatan Gupta const ManagedObjectType& ldapObjects) { 1406973a582SRatan Gupta LDAPConfigData confData{}; 1416973a582SRatan Gupta if (error_code) 1426973a582SRatan Gupta { 1436973a582SRatan Gupta callback(false, confData); 1446973a582SRatan Gupta BMCWEB_LOG_ERROR << "D-Bus responses error: " << error_code; 1456973a582SRatan Gupta return; 1466973a582SRatan Gupta } 1476973a582SRatan Gupta std::string ldapConfigObjectStr = std::string(ldapConfigObject); 1486973a582SRatan Gupta std::string ldapEnableInterfaceStr = std::string(ldapEnableInterface); 1496973a582SRatan Gupta std::string ldapConfigInterfaceStr = std::string(ldapConfigInterface); 1506973a582SRatan Gupta for (const auto& object : ldapObjects) 1516973a582SRatan Gupta { 1526973a582SRatan Gupta if (object.first == ldapConfigObjectStr) 1536973a582SRatan Gupta { 1546973a582SRatan Gupta for (const auto& interface : object.second) 1556973a582SRatan Gupta { 1566973a582SRatan Gupta if (interface.first == ldapEnableInterfaceStr) 1576973a582SRatan Gupta { 1586973a582SRatan Gupta // rest of the properties are string. 1596973a582SRatan Gupta for (const auto& property : interface.second) 1606973a582SRatan Gupta { 1616973a582SRatan Gupta if (property.first == "Enabled") 1626973a582SRatan Gupta { 1636973a582SRatan Gupta const bool* value = 1646973a582SRatan Gupta std::get_if<bool>(&property.second); 1656973a582SRatan Gupta if (value == nullptr) 1666973a582SRatan Gupta { 1676973a582SRatan Gupta continue; 1686973a582SRatan Gupta } 1696973a582SRatan Gupta confData.serviceEnabled = *value; 1706973a582SRatan Gupta break; 1716973a582SRatan Gupta } 1726973a582SRatan Gupta } 1736973a582SRatan Gupta } 1746973a582SRatan Gupta else if (interface.first == ldapConfigInterfaceStr) 1756973a582SRatan Gupta { 1766973a582SRatan Gupta 1776973a582SRatan Gupta for (const auto& property : interface.second) 1786973a582SRatan Gupta { 1796973a582SRatan Gupta const std::string* value = 1806973a582SRatan Gupta std::get_if<std::string>(&property.second); 1816973a582SRatan Gupta if (value == nullptr) 1826973a582SRatan Gupta { 1836973a582SRatan Gupta continue; 1846973a582SRatan Gupta } 1856973a582SRatan Gupta if (property.first == "LDAPServerURI") 1866973a582SRatan Gupta { 1876973a582SRatan Gupta confData.uri = *value; 1886973a582SRatan Gupta } 1896973a582SRatan Gupta else if (property.first == "LDAPBindDN") 1906973a582SRatan Gupta { 1916973a582SRatan Gupta confData.bindDN = *value; 1926973a582SRatan Gupta } 1936973a582SRatan Gupta else if (property.first == "LDAPBaseDN") 1946973a582SRatan Gupta { 1956973a582SRatan Gupta confData.baseDN = *value; 1966973a582SRatan Gupta } 1976973a582SRatan Gupta else if (property.first == "LDAPSearchScope") 1986973a582SRatan Gupta { 1996973a582SRatan Gupta confData.searchScope = *value; 2006973a582SRatan Gupta } 2016973a582SRatan Gupta else if (property.first == "LDAPType") 2026973a582SRatan Gupta { 2036973a582SRatan Gupta confData.serverType = *value; 2046973a582SRatan Gupta } 2056973a582SRatan Gupta else if (property.first == "GroupNameAttribute") 2066973a582SRatan Gupta { 2076973a582SRatan Gupta confData.groupAttribute = *value; 2086973a582SRatan Gupta } 2096973a582SRatan Gupta else if (property.first == "UserNameAttribute") 2106973a582SRatan Gupta { 2116973a582SRatan Gupta confData.userNameAttribute = *value; 2126973a582SRatan Gupta } 2136973a582SRatan Gupta } 2146973a582SRatan Gupta } 2156973a582SRatan Gupta } 2166973a582SRatan Gupta 2176973a582SRatan Gupta callback(true, confData); 2186973a582SRatan Gupta break; 2196973a582SRatan Gupta } 2206973a582SRatan Gupta } 2216973a582SRatan Gupta }; 2226973a582SRatan Gupta auto getServiceName = [callback, getConfig(std::move(getConfig))]( 2236973a582SRatan Gupta const boost::system::error_code ec, 2246973a582SRatan Gupta const GetObjectType& resp) { 2256973a582SRatan Gupta LDAPConfigData confData{}; 2266973a582SRatan Gupta if (ec || resp.empty()) 2276973a582SRatan Gupta { 2286973a582SRatan Gupta BMCWEB_LOG_ERROR 2296973a582SRatan Gupta << "DBUS response error during getting of service name: " << ec; 2306973a582SRatan Gupta callback(false, confData); 2316973a582SRatan Gupta return; 2326973a582SRatan Gupta } 2336973a582SRatan Gupta std::string service = resp.begin()->first; 2346973a582SRatan Gupta crow::connections::systemBus->async_method_call( 2356973a582SRatan Gupta std::move(getConfig), service, ldapRootObject, dbusObjManagerIntf, 2366973a582SRatan Gupta "GetManagedObjects"); 2376973a582SRatan Gupta }; 2386973a582SRatan Gupta 2396973a582SRatan Gupta const std::array<std::string, 2> interfaces = {ldapEnableInterface, 2406973a582SRatan Gupta ldapConfigInterface}; 2416973a582SRatan Gupta 2426973a582SRatan Gupta crow::connections::systemBus->async_method_call( 2436973a582SRatan Gupta std::move(getServiceName), mapperBusName, mapperObjectPath, mapperIntf, 2446973a582SRatan Gupta "GetObject", ldapConfigObject, interfaces); 2456973a582SRatan Gupta } 2466973a582SRatan 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: 2638a07d286SRatan Gupta /** 2648a07d286SRatan Gupta * @brief parses the authentication section under the LDAP 2658a07d286SRatan Gupta * @param input JSON data 2668a07d286SRatan Gupta * @param asyncResp pointer to the JSON response 2678a07d286SRatan Gupta * @param userName userName to be filled from the given JSON. 2688a07d286SRatan Gupta * @param password password to be filled from the given JSON. 2698a07d286SRatan Gupta */ 2708a07d286SRatan Gupta void 2718a07d286SRatan Gupta parseLDAPAuthenticationJson(nlohmann::json input, 2728a07d286SRatan Gupta const std::shared_ptr<AsyncResp>& asyncResp, 2738a07d286SRatan Gupta std::optional<std::string>& username, 2748a07d286SRatan Gupta std::optional<std::string>& password) 2758a07d286SRatan Gupta { 2768a07d286SRatan Gupta std::optional<std::string> authType; 2778a07d286SRatan Gupta 2788a07d286SRatan Gupta if (!json_util::readJson(input, asyncResp->res, "AuthenticationType", 2798a07d286SRatan Gupta authType, "Username", username, "Password", 2808a07d286SRatan Gupta password)) 2818a07d286SRatan Gupta { 2828a07d286SRatan Gupta return; 2838a07d286SRatan Gupta } 2848a07d286SRatan Gupta if (!authType) 2858a07d286SRatan Gupta { 2868a07d286SRatan Gupta return; 2878a07d286SRatan Gupta } 2888a07d286SRatan Gupta if (*authType != "UsernameAndPassword") 2898a07d286SRatan Gupta { 2908a07d286SRatan Gupta messages::propertyValueNotInList(asyncResp->res, *authType, 2918a07d286SRatan Gupta "AuthenticationType"); 2928a07d286SRatan Gupta return; 2938a07d286SRatan Gupta } 2948a07d286SRatan Gupta } 2958a07d286SRatan Gupta /** 2968a07d286SRatan Gupta * @brief parses the LDAPService section under the LDAP 2978a07d286SRatan Gupta * @param input JSON data 2988a07d286SRatan Gupta * @param asyncResp pointer to the JSON response 2998a07d286SRatan Gupta * @param baseDNList baseDN to be filled from the given JSON. 3008a07d286SRatan Gupta * @param userNameAttribute userName to be filled from the given JSON. 3018a07d286SRatan Gupta * @param groupaAttribute password to be filled from the given JSON. 3028a07d286SRatan Gupta */ 3038a07d286SRatan Gupta 3048a07d286SRatan Gupta void parseLDAPServiceJson( 3058a07d286SRatan Gupta nlohmann::json input, const std::shared_ptr<AsyncResp>& asyncResp, 3068a07d286SRatan Gupta std::optional<std::vector<std::string>>& baseDNList, 3078a07d286SRatan Gupta std::optional<std::string>& userNameAttribute, 3088a07d286SRatan Gupta std::optional<std::string>& groupsAttribute) 3098a07d286SRatan Gupta { 3108a07d286SRatan Gupta std::optional<nlohmann::json> searchSettings; 3118a07d286SRatan Gupta 3128a07d286SRatan Gupta if (!json_util::readJson(input, asyncResp->res, "SearchSettings", 3138a07d286SRatan Gupta searchSettings)) 3148a07d286SRatan Gupta { 3158a07d286SRatan Gupta return; 3168a07d286SRatan Gupta } 3178a07d286SRatan Gupta if (!searchSettings) 3188a07d286SRatan Gupta { 3198a07d286SRatan Gupta return; 3208a07d286SRatan Gupta } 3218a07d286SRatan Gupta if (!json_util::readJson(*searchSettings, asyncResp->res, 3228a07d286SRatan Gupta "BaseDistinguishedNames", baseDNList, 3238a07d286SRatan Gupta "UsernameAttribute", userNameAttribute, 3248a07d286SRatan Gupta "GroupsAttribute", groupsAttribute)) 3258a07d286SRatan Gupta { 3268a07d286SRatan Gupta return; 3278a07d286SRatan Gupta } 3288a07d286SRatan Gupta } 3298a07d286SRatan Gupta /** 3308a07d286SRatan Gupta * @brief updates the LDAP server address and updates the 3318a07d286SRatan Gupta json response with the new value. 3328a07d286SRatan Gupta * @param serviceAddressList address to be updated. 3338a07d286SRatan Gupta * @param asyncResp pointer to the JSON response 3348a07d286SRatan Gupta * @param ldapServerElementName Type of LDAP 3358a07d286SRatan Gupta server(openLDAP/ActiveDirectory) 3368a07d286SRatan Gupta */ 3378a07d286SRatan Gupta 3388a07d286SRatan Gupta void handleServiceAddressPatch( 3398a07d286SRatan Gupta const std::vector<std::string>& serviceAddressList, 3408a07d286SRatan Gupta const std::shared_ptr<AsyncResp>& asyncResp, 3418a07d286SRatan Gupta const std::string& ldapServerElementName, 3428a07d286SRatan Gupta const std::string& ldapConfigObject) 3438a07d286SRatan Gupta { 3448a07d286SRatan Gupta crow::connections::systemBus->async_method_call( 3458a07d286SRatan Gupta [asyncResp, ldapServerElementName, 3468a07d286SRatan Gupta serviceAddressList](const boost::system::error_code ec) { 3478a07d286SRatan Gupta if (ec) 3488a07d286SRatan Gupta { 3498a07d286SRatan Gupta BMCWEB_LOG_DEBUG 3508a07d286SRatan Gupta << "Error Occured in updating the service address"; 3518a07d286SRatan Gupta messages::internalError(asyncResp->res); 3528a07d286SRatan Gupta return; 3538a07d286SRatan Gupta } 3548a07d286SRatan Gupta std::vector<std::string> modifiedserviceAddressList = { 3558a07d286SRatan Gupta serviceAddressList.front()}; 3568a07d286SRatan Gupta asyncResp->res 3578a07d286SRatan Gupta .jsonValue[ldapServerElementName]["ServiceAddresses"] = 3588a07d286SRatan Gupta modifiedserviceAddressList; 3598a07d286SRatan Gupta if ((serviceAddressList).size() > 1) 3608a07d286SRatan Gupta { 3618a07d286SRatan Gupta messages::propertyValueModified(asyncResp->res, 3628a07d286SRatan Gupta "ServiceAddresses", 3638a07d286SRatan Gupta serviceAddressList.front()); 3648a07d286SRatan Gupta } 3658a07d286SRatan Gupta BMCWEB_LOG_DEBUG << "Updated the service address"; 3668a07d286SRatan Gupta }, 3678a07d286SRatan Gupta ldapDbusService, ldapConfigObject, propertyInterface, "Set", 3688a07d286SRatan Gupta ldapConfigInterface, "LDAPServerURI", 3698a07d286SRatan Gupta std::variant<std::string>(serviceAddressList.front())); 3708a07d286SRatan Gupta } 3718a07d286SRatan Gupta /** 3728a07d286SRatan Gupta * @brief updates the LDAP Bind DN and updates the 3738a07d286SRatan Gupta json response with the new value. 3748a07d286SRatan Gupta * @param username name of the user which needs 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 handleUserNamePatch(const std::string& username, 3818a07d286SRatan Gupta const std::shared_ptr<AsyncResp>& asyncResp, 3828a07d286SRatan Gupta const std::string& ldapServerElementName, 3838a07d286SRatan Gupta const std::string& ldapConfigObject) 3848a07d286SRatan Gupta { 3858a07d286SRatan Gupta crow::connections::systemBus->async_method_call( 3868a07d286SRatan Gupta [asyncResp, username, 3878a07d286SRatan Gupta ldapServerElementName](const boost::system::error_code ec) { 3888a07d286SRatan Gupta if (ec) 3898a07d286SRatan Gupta { 3908a07d286SRatan Gupta BMCWEB_LOG_DEBUG 3918a07d286SRatan Gupta << "Error occured in updating the username"; 3928a07d286SRatan Gupta messages::internalError(asyncResp->res); 3938a07d286SRatan Gupta return; 3948a07d286SRatan Gupta } 3958a07d286SRatan Gupta asyncResp->res.jsonValue[ldapServerElementName] 3968a07d286SRatan Gupta ["Authentication"]["Username"] = 3978a07d286SRatan Gupta username; 3988a07d286SRatan Gupta BMCWEB_LOG_DEBUG << "Updated the username"; 3998a07d286SRatan Gupta }, 4008a07d286SRatan Gupta ldapDbusService, ldapConfigObject, propertyInterface, "Set", 4018a07d286SRatan Gupta ldapConfigInterface, "LDAPBindDN", 4028a07d286SRatan Gupta std::variant<std::string>(username)); 4038a07d286SRatan Gupta } 4048a07d286SRatan Gupta 4058a07d286SRatan Gupta /** 4068a07d286SRatan Gupta * @brief updates the LDAP password 4078a07d286SRatan Gupta * @param password : ldap password which needs to be updated. 4088a07d286SRatan Gupta * @param asyncResp pointer to the JSON response 4098a07d286SRatan Gupta * @param ldapServerElementName Type of LDAP 4108a07d286SRatan Gupta * server(openLDAP/ActiveDirectory) 4118a07d286SRatan Gupta */ 4128a07d286SRatan Gupta 4138a07d286SRatan Gupta void handlePasswordPatch(const std::string& password, 4148a07d286SRatan Gupta const std::shared_ptr<AsyncResp>& asyncResp, 4158a07d286SRatan Gupta const std::string& ldapServerElementName, 4168a07d286SRatan Gupta const std::string& ldapConfigObject) 4178a07d286SRatan Gupta { 4188a07d286SRatan Gupta crow::connections::systemBus->async_method_call( 4198a07d286SRatan Gupta [asyncResp, password, 4208a07d286SRatan Gupta ldapServerElementName](const boost::system::error_code ec) { 4218a07d286SRatan Gupta if (ec) 4228a07d286SRatan Gupta { 4238a07d286SRatan Gupta BMCWEB_LOG_DEBUG 4248a07d286SRatan Gupta << "Error occured in updating the password"; 4258a07d286SRatan Gupta messages::internalError(asyncResp->res); 4268a07d286SRatan Gupta return; 4278a07d286SRatan Gupta } 4288a07d286SRatan Gupta asyncResp->res.jsonValue[ldapServerElementName] 4298a07d286SRatan Gupta ["Authentication"]["Password"] = ""; 4308a07d286SRatan Gupta BMCWEB_LOG_DEBUG << "Updated the password"; 4318a07d286SRatan Gupta }, 4328a07d286SRatan Gupta ldapDbusService, ldapConfigObject, propertyInterface, "Set", 4338a07d286SRatan Gupta ldapConfigInterface, "LDAPBindDNPassword", 4348a07d286SRatan Gupta std::variant<std::string>(password)); 4358a07d286SRatan Gupta } 4368a07d286SRatan Gupta 4378a07d286SRatan Gupta /** 4388a07d286SRatan Gupta * @brief updates the LDAP BaseDN and updates the 4398a07d286SRatan Gupta json response with the new value. 4408a07d286SRatan Gupta * @param baseDNList baseDN list which needs to be updated. 4418a07d286SRatan Gupta * @param asyncResp pointer to the JSON response 4428a07d286SRatan Gupta * @param ldapServerElementName Type of LDAP 4438a07d286SRatan Gupta server(openLDAP/ActiveDirectory) 4448a07d286SRatan Gupta */ 4458a07d286SRatan Gupta 4468a07d286SRatan Gupta void handleBaseDNPatch(const std::vector<std::string>& baseDNList, 4478a07d286SRatan Gupta const std::shared_ptr<AsyncResp>& asyncResp, 4488a07d286SRatan Gupta const std::string& ldapServerElementName, 4498a07d286SRatan Gupta const std::string& ldapConfigObject) 4508a07d286SRatan Gupta { 4518a07d286SRatan Gupta crow::connections::systemBus->async_method_call( 4528a07d286SRatan Gupta [asyncResp, baseDNList, 4538a07d286SRatan Gupta ldapServerElementName](const boost::system::error_code ec) { 4548a07d286SRatan Gupta if (ec) 4558a07d286SRatan Gupta { 4568a07d286SRatan Gupta BMCWEB_LOG_DEBUG << "Error Occured in Updating the base DN"; 4578a07d286SRatan Gupta messages::internalError(asyncResp->res); 4588a07d286SRatan Gupta return; 4598a07d286SRatan Gupta } 4608a07d286SRatan Gupta auto& serverTypeJson = 4618a07d286SRatan Gupta asyncResp->res.jsonValue[ldapServerElementName]; 4628a07d286SRatan Gupta auto& searchSettingsJson = 4638a07d286SRatan Gupta serverTypeJson["LDAPService"]["SearchSettings"]; 4648a07d286SRatan Gupta std::vector<std::string> modifiedBaseDNList = { 4658a07d286SRatan Gupta baseDNList.front()}; 4668a07d286SRatan Gupta searchSettingsJson["BaseDistinguishedNames"] = 4678a07d286SRatan Gupta modifiedBaseDNList; 4688a07d286SRatan Gupta if (baseDNList.size() > 1) 4698a07d286SRatan Gupta { 4708a07d286SRatan Gupta messages::propertyValueModified(asyncResp->res, 4718a07d286SRatan Gupta "BaseDistinguishedNames", 4728a07d286SRatan Gupta baseDNList.front()); 4738a07d286SRatan Gupta } 4748a07d286SRatan Gupta BMCWEB_LOG_DEBUG << "Updated the base DN"; 4758a07d286SRatan Gupta }, 4768a07d286SRatan Gupta ldapDbusService, ldapConfigObject, propertyInterface, "Set", 4778a07d286SRatan Gupta ldapConfigInterface, "LDAPBaseDN", 4788a07d286SRatan Gupta std::variant<std::string>(baseDNList.front())); 4798a07d286SRatan Gupta } 4808a07d286SRatan Gupta /** 4818a07d286SRatan Gupta * @brief updates the LDAP user name attribute and updates the 4828a07d286SRatan Gupta json response with the new value. 4838a07d286SRatan Gupta * @param userNameAttribute attribute to be updated. 4848a07d286SRatan Gupta * @param asyncResp pointer to the JSON response 4858a07d286SRatan Gupta * @param ldapServerElementName Type of LDAP 4868a07d286SRatan Gupta server(openLDAP/ActiveDirectory) 4878a07d286SRatan Gupta */ 4888a07d286SRatan Gupta 4898a07d286SRatan Gupta void handleUserNameAttrPatch(const std::string& userNameAttribute, 4908a07d286SRatan Gupta const std::shared_ptr<AsyncResp>& asyncResp, 4918a07d286SRatan Gupta const std::string& ldapServerElementName, 4928a07d286SRatan Gupta const std::string& ldapConfigObject) 4938a07d286SRatan Gupta { 4948a07d286SRatan Gupta crow::connections::systemBus->async_method_call( 4958a07d286SRatan Gupta [asyncResp, userNameAttribute, 4968a07d286SRatan Gupta ldapServerElementName](const boost::system::error_code ec) { 4978a07d286SRatan Gupta if (ec) 4988a07d286SRatan Gupta { 4998a07d286SRatan Gupta BMCWEB_LOG_DEBUG << "Error Occured in Updating the " 5008a07d286SRatan Gupta "username attribute"; 5018a07d286SRatan Gupta messages::internalError(asyncResp->res); 5028a07d286SRatan Gupta return; 5038a07d286SRatan Gupta } 5048a07d286SRatan Gupta auto& serverTypeJson = 5058a07d286SRatan Gupta asyncResp->res.jsonValue[ldapServerElementName]; 5068a07d286SRatan Gupta auto& searchSettingsJson = 5078a07d286SRatan Gupta serverTypeJson["LDAPService"]["SearchSettings"]; 5088a07d286SRatan Gupta searchSettingsJson["UsernameAttribute"] = userNameAttribute; 5098a07d286SRatan Gupta BMCWEB_LOG_DEBUG << "Updated the user name attr."; 5108a07d286SRatan Gupta }, 5118a07d286SRatan Gupta ldapDbusService, ldapConfigObject, propertyInterface, "Set", 5128a07d286SRatan Gupta ldapConfigInterface, "UserNameAttribute", 5138a07d286SRatan Gupta std::variant<std::string>(userNameAttribute)); 5148a07d286SRatan Gupta } 5158a07d286SRatan Gupta /** 5168a07d286SRatan Gupta * @brief updates the LDAP group attribute and updates the 5178a07d286SRatan Gupta json response with the new value. 5188a07d286SRatan Gupta * @param groupsAttribute attribute to be updated. 5198a07d286SRatan Gupta * @param asyncResp pointer to the JSON response 5208a07d286SRatan Gupta * @param ldapServerElementName Type of LDAP 5218a07d286SRatan Gupta server(openLDAP/ActiveDirectory) 5228a07d286SRatan Gupta */ 5238a07d286SRatan Gupta 5248a07d286SRatan Gupta void handleGroupNameAttrPatch(const std::string& groupsAttribute, 5258a07d286SRatan Gupta const std::shared_ptr<AsyncResp>& asyncResp, 5268a07d286SRatan Gupta const std::string& ldapServerElementName, 5278a07d286SRatan Gupta const std::string& ldapConfigObject) 5288a07d286SRatan Gupta { 5298a07d286SRatan Gupta crow::connections::systemBus->async_method_call( 5308a07d286SRatan Gupta [asyncResp, groupsAttribute, 5318a07d286SRatan Gupta ldapServerElementName](const boost::system::error_code ec) { 5328a07d286SRatan Gupta if (ec) 5338a07d286SRatan Gupta { 5348a07d286SRatan Gupta BMCWEB_LOG_DEBUG << "Error Occured in Updating the " 5358a07d286SRatan Gupta "groupname attribute"; 5368a07d286SRatan Gupta messages::internalError(asyncResp->res); 5378a07d286SRatan Gupta return; 5388a07d286SRatan Gupta } 5398a07d286SRatan Gupta auto& serverTypeJson = 5408a07d286SRatan Gupta asyncResp->res.jsonValue[ldapServerElementName]; 5418a07d286SRatan Gupta auto& searchSettingsJson = 5428a07d286SRatan Gupta serverTypeJson["LDAPService"]["SearchSettings"]; 5438a07d286SRatan Gupta searchSettingsJson["GroupsAttribute"] = groupsAttribute; 5448a07d286SRatan Gupta BMCWEB_LOG_DEBUG << "Updated the groupname attr"; 5458a07d286SRatan Gupta }, 5468a07d286SRatan Gupta ldapDbusService, ldapConfigObject, propertyInterface, "Set", 5478a07d286SRatan Gupta ldapConfigInterface, "GroupNameAttribute", 5488a07d286SRatan Gupta std::variant<std::string>(groupsAttribute)); 5498a07d286SRatan Gupta } 5508a07d286SRatan Gupta /** 5518a07d286SRatan Gupta * @brief updates the LDAP service enable and updates the 5528a07d286SRatan Gupta json response with the new value. 5538a07d286SRatan Gupta * @param input JSON data. 5548a07d286SRatan Gupta * @param asyncResp pointer to the JSON response 5558a07d286SRatan Gupta * @param ldapServerElementName Type of LDAP 5568a07d286SRatan Gupta server(openLDAP/ActiveDirectory) 5578a07d286SRatan Gupta */ 5588a07d286SRatan Gupta 5598a07d286SRatan Gupta void handleServiceEnablePatch(bool serviceEnabled, 5608a07d286SRatan Gupta const std::shared_ptr<AsyncResp>& asyncResp, 5618a07d286SRatan Gupta const std::string& ldapServerElementName, 5628a07d286SRatan Gupta const std::string& ldapConfigObject) 5638a07d286SRatan Gupta { 5648a07d286SRatan Gupta crow::connections::systemBus->async_method_call( 5658a07d286SRatan Gupta [asyncResp, serviceEnabled, 5668a07d286SRatan Gupta ldapServerElementName](const boost::system::error_code ec) { 5678a07d286SRatan Gupta if (ec) 5688a07d286SRatan Gupta { 5698a07d286SRatan Gupta BMCWEB_LOG_DEBUG 5708a07d286SRatan Gupta << "Error Occured in Updating the service enable"; 5718a07d286SRatan Gupta messages::internalError(asyncResp->res); 5728a07d286SRatan Gupta return; 5738a07d286SRatan Gupta } 5748a07d286SRatan Gupta asyncResp->res 5758a07d286SRatan Gupta .jsonValue[ldapServerElementName]["ServiceEnabled"] = 5768a07d286SRatan Gupta serviceEnabled; 5778a07d286SRatan Gupta BMCWEB_LOG_DEBUG << "Updated Service enable = " 5788a07d286SRatan Gupta << serviceEnabled; 5798a07d286SRatan Gupta }, 5808a07d286SRatan Gupta ldapDbusService, ldapConfigObject, propertyInterface, "Set", 5818a07d286SRatan Gupta ldapEnableInterface, "Enabled", std::variant<bool>(serviceEnabled)); 5828a07d286SRatan Gupta } 5838a07d286SRatan Gupta 5848a07d286SRatan Gupta /** 5858a07d286SRatan Gupta * @brief Get the required values from the given JSON, validates the 5868a07d286SRatan Gupta * value and create the LDAP config object. 5878a07d286SRatan Gupta * @param input JSON data 5888a07d286SRatan Gupta * @param asyncResp pointer to the JSON response 5898a07d286SRatan Gupta * @param serverType Type of LDAP server(openLDAP/ActiveDirectory) 5908a07d286SRatan Gupta */ 5918a07d286SRatan Gupta 5928a07d286SRatan Gupta void handleLDAPPatch(nlohmann::json& input, 5938a07d286SRatan Gupta const std::shared_ptr<AsyncResp>& asyncResp, 5948a07d286SRatan Gupta const crow::Request& req, 5958a07d286SRatan Gupta const std::vector<std::string>& params, 5968a07d286SRatan Gupta const std::string& serverType) 5978a07d286SRatan Gupta { 5988a07d286SRatan Gupta std::optional<nlohmann::json> authentication; 5998a07d286SRatan Gupta std::optional<nlohmann::json> ldapService; 6008a07d286SRatan Gupta std::optional<std::string> accountProviderType; 6018a07d286SRatan Gupta std::optional<std::vector<std::string>> serviceAddressList; 6028a07d286SRatan Gupta std::optional<bool> serviceEnabled; 6038a07d286SRatan Gupta std::optional<std::vector<std::string>> baseDNList; 6048a07d286SRatan Gupta std::optional<std::string> userNameAttribute; 6058a07d286SRatan Gupta std::optional<std::string> groupsAttribute; 6068a07d286SRatan Gupta std::optional<std::string> userName; 6078a07d286SRatan Gupta std::optional<std::string> password; 6088a07d286SRatan Gupta 6098a07d286SRatan Gupta if (!json_util::readJson(input, asyncResp->res, "Authentication", 6108a07d286SRatan Gupta authentication, "LDAPService", ldapService, 6118a07d286SRatan Gupta "ServiceAddresses", serviceAddressList, 6128a07d286SRatan Gupta "AccountProviderType", accountProviderType, 6138a07d286SRatan Gupta "ServiceEnabled", serviceEnabled)) 6148a07d286SRatan Gupta { 6158a07d286SRatan Gupta return; 6168a07d286SRatan Gupta } 6178a07d286SRatan Gupta 6188a07d286SRatan Gupta if (authentication) 6198a07d286SRatan Gupta { 6208a07d286SRatan Gupta parseLDAPAuthenticationJson(*authentication, asyncResp, userName, 6218a07d286SRatan Gupta password); 6228a07d286SRatan Gupta } 6238a07d286SRatan Gupta if (ldapService) 6248a07d286SRatan Gupta { 6258a07d286SRatan Gupta parseLDAPServiceJson(*ldapService, asyncResp, baseDNList, 6268a07d286SRatan Gupta userNameAttribute, groupsAttribute); 6278a07d286SRatan Gupta } 6288a07d286SRatan Gupta if (accountProviderType) 6298a07d286SRatan Gupta { 6308a07d286SRatan Gupta messages::propertyNotWritable(asyncResp->res, 6318a07d286SRatan Gupta "AccountProviderType"); 6328a07d286SRatan Gupta } 6338a07d286SRatan Gupta if (serviceAddressList) 6348a07d286SRatan Gupta { 6358a07d286SRatan Gupta if ((*serviceAddressList).size() == 0) 6368a07d286SRatan Gupta { 6378a07d286SRatan Gupta messages::propertyValueNotInList(asyncResp->res, "[]", 6388a07d286SRatan Gupta "ServiceAddress"); 6398a07d286SRatan Gupta return; 6408a07d286SRatan Gupta } 6418a07d286SRatan Gupta } 6428a07d286SRatan Gupta if (baseDNList) 6438a07d286SRatan Gupta { 6448a07d286SRatan Gupta if ((*baseDNList).size() == 0) 6458a07d286SRatan Gupta { 6468a07d286SRatan Gupta messages::propertyValueNotInList(asyncResp->res, "[]", 6478a07d286SRatan Gupta "BaseDistinguishedNames"); 6488a07d286SRatan Gupta return; 6498a07d286SRatan Gupta } 6508a07d286SRatan Gupta } 6518a07d286SRatan Gupta 6528a07d286SRatan Gupta // nothing to update, then return 6538a07d286SRatan Gupta if (!userName && !password && !serviceAddressList && !baseDNList && 6548a07d286SRatan Gupta !userNameAttribute && !groupsAttribute && !serviceEnabled) 6558a07d286SRatan Gupta { 6568a07d286SRatan Gupta return; 6578a07d286SRatan Gupta } 6588a07d286SRatan Gupta 6598a07d286SRatan Gupta // Get the existing resource first then keep modifying 6608a07d286SRatan Gupta // whenever any property gets updated. 6618a07d286SRatan Gupta getLDAPConfigData( 6628a07d286SRatan Gupta serverType, 6638a07d286SRatan Gupta [this, asyncResp, userName, password, baseDNList, userNameAttribute, 6648a07d286SRatan Gupta groupsAttribute, accountProviderType, serviceAddressList, 6658a07d286SRatan Gupta serviceEnabled, 6668a07d286SRatan Gupta serverType](bool success, LDAPConfigData confData) { 6678a07d286SRatan Gupta if (!success) 6688a07d286SRatan Gupta { 6698a07d286SRatan Gupta messages::internalError(asyncResp->res); 6708a07d286SRatan Gupta return; 6718a07d286SRatan Gupta } 6728a07d286SRatan Gupta parseLDAPConfigData(asyncResp->res.jsonValue, confData); 6738a07d286SRatan Gupta if (confData.serviceEnabled) 6748a07d286SRatan Gupta { 6758a07d286SRatan Gupta // Disable the service first and update the rest of 6768a07d286SRatan Gupta // the properties. 6778a07d286SRatan Gupta handleServiceEnablePatch(false, asyncResp, serverType, 6788a07d286SRatan Gupta ldapConfigObject); 6798a07d286SRatan Gupta } 6808a07d286SRatan Gupta 6818a07d286SRatan Gupta if (serviceAddressList) 6828a07d286SRatan Gupta { 6838a07d286SRatan Gupta handleServiceAddressPatch(*serviceAddressList, asyncResp, 6848a07d286SRatan Gupta serverType, ldapConfigObject); 6858a07d286SRatan Gupta } 6868a07d286SRatan Gupta if (userName) 6878a07d286SRatan Gupta { 6888a07d286SRatan Gupta handleUserNamePatch(*userName, asyncResp, serverType, 6898a07d286SRatan Gupta ldapConfigObject); 6908a07d286SRatan Gupta } 6918a07d286SRatan Gupta if (password) 6928a07d286SRatan Gupta { 6938a07d286SRatan Gupta handlePasswordPatch(*password, asyncResp, serverType, 6948a07d286SRatan Gupta ldapConfigObject); 6958a07d286SRatan Gupta } 6968a07d286SRatan Gupta 6978a07d286SRatan Gupta if (baseDNList) 6988a07d286SRatan Gupta { 6998a07d286SRatan Gupta handleBaseDNPatch(*baseDNList, asyncResp, serverType, 7008a07d286SRatan Gupta ldapConfigObject); 7018a07d286SRatan Gupta } 7028a07d286SRatan Gupta if (userNameAttribute) 7038a07d286SRatan Gupta { 7048a07d286SRatan Gupta handleUserNameAttrPatch(*userNameAttribute, asyncResp, 7058a07d286SRatan Gupta serverType, ldapConfigObject); 7068a07d286SRatan Gupta } 7078a07d286SRatan Gupta if (groupsAttribute) 7088a07d286SRatan Gupta { 7098a07d286SRatan Gupta handleGroupNameAttrPatch(*groupsAttribute, asyncResp, 7108a07d286SRatan Gupta serverType, ldapConfigObject); 7118a07d286SRatan Gupta } 7128a07d286SRatan Gupta if (serviceEnabled) 7138a07d286SRatan Gupta { 7148a07d286SRatan Gupta // if user has given the value as true then enable 7158a07d286SRatan Gupta // the service. if user has given false then no-op 7168a07d286SRatan Gupta // as service is already stopped. 7178a07d286SRatan Gupta if (*serviceEnabled) 7188a07d286SRatan Gupta { 7198a07d286SRatan Gupta handleServiceEnablePatch(*serviceEnabled, asyncResp, 7208a07d286SRatan Gupta serverType, ldapConfigObject); 7218a07d286SRatan Gupta } 7228a07d286SRatan Gupta } 7238a07d286SRatan Gupta else 7248a07d286SRatan Gupta { 7258a07d286SRatan Gupta // if user has not given the service enabled value 7268a07d286SRatan Gupta // then revert it to the same state as it was 7278a07d286SRatan Gupta // before. 7288a07d286SRatan Gupta handleServiceEnablePatch(confData.serviceEnabled, asyncResp, 7298a07d286SRatan Gupta serverType, ldapConfigObject); 7308a07d286SRatan Gupta } 7318a07d286SRatan Gupta }); 7328a07d286SRatan Gupta } 7338a07d286SRatan Gupta 73455c7b7a2SEd Tanous void doGet(crow::Response& res, const crow::Request& req, 7351abe55efSEd Tanous const std::vector<std::string>& params) override 7361abe55efSEd Tanous { 7373d958bbcSAppaRao Puli auto asyncResp = std::make_shared<AsyncResp>(res); 7383d958bbcSAppaRao Puli res.jsonValue = { 7393d958bbcSAppaRao Puli {"@odata.context", "/redfish/v1/" 7403d958bbcSAppaRao Puli "$metadata#AccountService.AccountService"}, 7413d958bbcSAppaRao Puli {"@odata.id", "/redfish/v1/AccountService"}, 7423d958bbcSAppaRao Puli {"@odata.type", "#AccountService." 7436973a582SRatan Gupta "v1_3_1.AccountService"}, 7443d958bbcSAppaRao Puli {"Id", "AccountService"}, 7453d958bbcSAppaRao Puli {"Name", "Account Service"}, 7463d958bbcSAppaRao Puli {"Description", "Account Service"}, 7473d958bbcSAppaRao Puli {"ServiceEnabled", true}, 748343ff2e1SAppaRao Puli {"MaxPasswordLength", 20}, 7493d958bbcSAppaRao Puli {"Accounts", 7503d958bbcSAppaRao Puli {{"@odata.id", "/redfish/v1/AccountService/Accounts"}}}, 7513d958bbcSAppaRao Puli {"Roles", {{"@odata.id", "/redfish/v1/AccountService/Roles"}}}}; 7520f74e643SEd Tanous 7533d958bbcSAppaRao Puli crow::connections::systemBus->async_method_call( 7543d958bbcSAppaRao Puli [asyncResp]( 7553d958bbcSAppaRao Puli const boost::system::error_code ec, 7563d958bbcSAppaRao Puli const std::vector<std::pair< 757abf2add6SEd Tanous std::string, std::variant<uint32_t, uint16_t, uint8_t>>>& 7583d958bbcSAppaRao Puli propertiesList) { 7593d958bbcSAppaRao Puli if (ec) 7603d958bbcSAppaRao Puli { 7613d958bbcSAppaRao Puli messages::internalError(asyncResp->res); 7623d958bbcSAppaRao Puli return; 7633d958bbcSAppaRao Puli } 7643d958bbcSAppaRao Puli BMCWEB_LOG_DEBUG << "Got " << propertiesList.size() 7653d958bbcSAppaRao Puli << "properties for AccountService"; 7663d958bbcSAppaRao Puli for (const std::pair<std::string, 767abf2add6SEd Tanous std::variant<uint32_t, uint16_t, uint8_t>>& 7683d958bbcSAppaRao Puli property : propertiesList) 7693d958bbcSAppaRao Puli { 7703d958bbcSAppaRao Puli if (property.first == "MinPasswordLength") 7713d958bbcSAppaRao Puli { 7723d958bbcSAppaRao Puli const uint8_t* value = 773abf2add6SEd Tanous std::get_if<uint8_t>(&property.second); 7743d958bbcSAppaRao Puli if (value != nullptr) 7753d958bbcSAppaRao Puli { 7763d958bbcSAppaRao Puli asyncResp->res.jsonValue["MinPasswordLength"] = 7773d958bbcSAppaRao Puli *value; 7783d958bbcSAppaRao Puli } 7793d958bbcSAppaRao Puli } 7803d958bbcSAppaRao Puli if (property.first == "AccountUnlockTimeout") 7813d958bbcSAppaRao Puli { 7823d958bbcSAppaRao Puli const uint32_t* value = 783abf2add6SEd Tanous std::get_if<uint32_t>(&property.second); 7843d958bbcSAppaRao Puli if (value != nullptr) 7853d958bbcSAppaRao Puli { 7863d958bbcSAppaRao Puli asyncResp->res.jsonValue["AccountLockoutDuration"] = 7873d958bbcSAppaRao Puli *value; 7883d958bbcSAppaRao Puli } 7893d958bbcSAppaRao Puli } 7903d958bbcSAppaRao Puli if (property.first == "MaxLoginAttemptBeforeLockout") 7913d958bbcSAppaRao Puli { 7923d958bbcSAppaRao Puli const uint16_t* value = 793abf2add6SEd Tanous std::get_if<uint16_t>(&property.second); 7943d958bbcSAppaRao Puli if (value != nullptr) 7953d958bbcSAppaRao Puli { 7963d958bbcSAppaRao Puli asyncResp->res 7973d958bbcSAppaRao Puli .jsonValue["AccountLockoutThreshold"] = *value; 7983d958bbcSAppaRao Puli } 7993d958bbcSAppaRao Puli } 8003d958bbcSAppaRao Puli } 8013d958bbcSAppaRao Puli }, 8023d958bbcSAppaRao Puli "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user", 8033d958bbcSAppaRao Puli "org.freedesktop.DBus.Properties", "GetAll", 8043d958bbcSAppaRao Puli "xyz.openbmc_project.User.AccountPolicy"); 8056973a582SRatan Gupta 8066973a582SRatan Gupta std::string ldapType = "LDAP"; 8076973a582SRatan Gupta getLDAPConfigData( 8086973a582SRatan Gupta ldapType, 8096973a582SRatan Gupta [asyncResp, ldapType](bool success, LDAPConfigData& confData) { 8106973a582SRatan Gupta parseLDAPConfigData(asyncResp->res.jsonValue, confData); 8116973a582SRatan Gupta }); 8123d958bbcSAppaRao Puli } 8136973a582SRatan Gupta 8143d958bbcSAppaRao Puli void doPatch(crow::Response& res, const crow::Request& req, 8153d958bbcSAppaRao Puli const std::vector<std::string>& params) override 8163d958bbcSAppaRao Puli { 8173d958bbcSAppaRao Puli auto asyncResp = std::make_shared<AsyncResp>(res); 8183d958bbcSAppaRao Puli 8193d958bbcSAppaRao Puli std::optional<uint32_t> unlockTimeout; 8203d958bbcSAppaRao Puli std::optional<uint16_t> lockoutThreshold; 82119fb6e71SRatan Gupta std::optional<uint16_t> minPasswordLength; 82219fb6e71SRatan Gupta std::optional<uint16_t> maxPasswordLength; 8238a07d286SRatan Gupta std::optional<nlohmann::json> ldapObject; 82419fb6e71SRatan Gupta 8253d958bbcSAppaRao Puli if (!json_util::readJson(req, res, "AccountLockoutDuration", 8263d958bbcSAppaRao Puli unlockTimeout, "AccountLockoutThreshold", 82719fb6e71SRatan Gupta lockoutThreshold, "MaxPasswordLength", 82819fb6e71SRatan Gupta maxPasswordLength, "MinPasswordLength", 82919fb6e71SRatan Gupta minPasswordLength)) 8303d958bbcSAppaRao Puli { 8313d958bbcSAppaRao Puli return; 8323d958bbcSAppaRao Puli } 83319fb6e71SRatan Gupta 83419fb6e71SRatan Gupta if (minPasswordLength) 83519fb6e71SRatan Gupta { 83619fb6e71SRatan Gupta messages::propertyNotWritable(asyncResp->res, "MinPasswordLength"); 83719fb6e71SRatan Gupta } 83819fb6e71SRatan Gupta 83919fb6e71SRatan Gupta if (maxPasswordLength) 84019fb6e71SRatan Gupta { 84119fb6e71SRatan Gupta messages::propertyNotWritable(asyncResp->res, "MaxPasswordLength"); 84219fb6e71SRatan Gupta } 84319fb6e71SRatan Gupta 8448a07d286SRatan Gupta if (ldapObject) 8458a07d286SRatan Gupta { 8468a07d286SRatan Gupta handleLDAPPatch(*ldapObject, asyncResp, req, params, "LDAP"); 8478a07d286SRatan Gupta } 8488a07d286SRatan Gupta 8493d958bbcSAppaRao Puli if (unlockTimeout) 8503d958bbcSAppaRao Puli { 8513d958bbcSAppaRao Puli crow::connections::systemBus->async_method_call( 8523d958bbcSAppaRao Puli [asyncResp](const boost::system::error_code ec) { 8533d958bbcSAppaRao Puli if (ec) 8543d958bbcSAppaRao Puli { 8553d958bbcSAppaRao Puli messages::internalError(asyncResp->res); 8563d958bbcSAppaRao Puli return; 8573d958bbcSAppaRao Puli } 858add6133bSRatan Gupta messages::success(asyncResp->res); 8593d958bbcSAppaRao Puli }, 8603d958bbcSAppaRao Puli "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user", 8613d958bbcSAppaRao Puli "org.freedesktop.DBus.Properties", "Set", 8623d958bbcSAppaRao Puli "xyz.openbmc_project.User.AccountPolicy", 863abf2add6SEd Tanous "AccountUnlockTimeout", std::variant<uint32_t>(*unlockTimeout)); 8643d958bbcSAppaRao Puli } 8653d958bbcSAppaRao Puli if (lockoutThreshold) 8663d958bbcSAppaRao Puli { 8673d958bbcSAppaRao Puli crow::connections::systemBus->async_method_call( 8683d958bbcSAppaRao Puli [asyncResp](const boost::system::error_code ec) { 8693d958bbcSAppaRao Puli if (ec) 8703d958bbcSAppaRao Puli { 8713d958bbcSAppaRao Puli messages::internalError(asyncResp->res); 8723d958bbcSAppaRao Puli return; 8733d958bbcSAppaRao Puli } 874add6133bSRatan Gupta messages::success(asyncResp->res); 8753d958bbcSAppaRao Puli }, 8763d958bbcSAppaRao Puli "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user", 8773d958bbcSAppaRao Puli "org.freedesktop.DBus.Properties", "Set", 8783d958bbcSAppaRao Puli "xyz.openbmc_project.User.AccountPolicy", 8793d958bbcSAppaRao Puli "MaxLoginAttemptBeforeLockout", 880abf2add6SEd Tanous std::variant<uint16_t>(*lockoutThreshold)); 8813d958bbcSAppaRao Puli } 88288d16c9aSLewanczyk, Dawid } 88388d16c9aSLewanczyk, Dawid }; 884f00032dbSTanous 885b9b2e0b2SEd Tanous class AccountsCollection : public Node 886b9b2e0b2SEd Tanous { 887b9b2e0b2SEd Tanous public: 888b9b2e0b2SEd Tanous AccountsCollection(CrowApp& app) : 889b9b2e0b2SEd Tanous Node(app, "/redfish/v1/AccountService/Accounts/") 890b9b2e0b2SEd Tanous { 891b9b2e0b2SEd Tanous entityPrivileges = { 892b9b2e0b2SEd Tanous {boost::beast::http::verb::get, 893b9b2e0b2SEd Tanous {{"ConfigureUsers"}, {"ConfigureManager"}}}, 894b9b2e0b2SEd Tanous {boost::beast::http::verb::head, {{"Login"}}}, 895b9b2e0b2SEd Tanous {boost::beast::http::verb::patch, {{"ConfigureUsers"}}}, 896b9b2e0b2SEd Tanous {boost::beast::http::verb::put, {{"ConfigureUsers"}}}, 897b9b2e0b2SEd Tanous {boost::beast::http::verb::delete_, {{"ConfigureUsers"}}}, 898b9b2e0b2SEd Tanous {boost::beast::http::verb::post, {{"ConfigureUsers"}}}}; 899b9b2e0b2SEd Tanous } 900b9b2e0b2SEd Tanous 901b9b2e0b2SEd Tanous private: 902b9b2e0b2SEd Tanous void doGet(crow::Response& res, const crow::Request& req, 903b9b2e0b2SEd Tanous const std::vector<std::string>& params) override 904b9b2e0b2SEd Tanous { 905b9b2e0b2SEd Tanous auto asyncResp = std::make_shared<AsyncResp>(res); 9060f74e643SEd Tanous res.jsonValue = {{"@odata.context", 9070f74e643SEd Tanous "/redfish/v1/" 9080f74e643SEd Tanous "$metadata#ManagerAccountCollection." 9090f74e643SEd Tanous "ManagerAccountCollection"}, 9100f74e643SEd Tanous {"@odata.id", "/redfish/v1/AccountService/Accounts"}, 9110f74e643SEd Tanous {"@odata.type", "#ManagerAccountCollection." 9120f74e643SEd Tanous "ManagerAccountCollection"}, 9130f74e643SEd Tanous {"Name", "Accounts Collection"}, 9140f74e643SEd Tanous {"Description", "BMC User Accounts"}}; 9150f74e643SEd Tanous 916b9b2e0b2SEd Tanous crow::connections::systemBus->async_method_call( 917b9b2e0b2SEd Tanous [asyncResp](const boost::system::error_code ec, 918b9b2e0b2SEd Tanous const ManagedObjectType& users) { 919b9b2e0b2SEd Tanous if (ec) 920b9b2e0b2SEd Tanous { 921f12894f8SJason M. Bills messages::internalError(asyncResp->res); 922b9b2e0b2SEd Tanous return; 923b9b2e0b2SEd Tanous } 924b9b2e0b2SEd Tanous 925b9b2e0b2SEd Tanous nlohmann::json& memberArray = 926b9b2e0b2SEd Tanous asyncResp->res.jsonValue["Members"]; 927b9b2e0b2SEd Tanous memberArray = nlohmann::json::array(); 928b9b2e0b2SEd Tanous 929b9b2e0b2SEd Tanous asyncResp->res.jsonValue["Members@odata.count"] = users.size(); 930b9b2e0b2SEd Tanous for (auto& user : users) 931b9b2e0b2SEd Tanous { 932b9b2e0b2SEd Tanous const std::string& path = 933b9b2e0b2SEd Tanous static_cast<const std::string&>(user.first); 934b9b2e0b2SEd Tanous std::size_t lastIndex = path.rfind("/"); 935b9b2e0b2SEd Tanous if (lastIndex == std::string::npos) 936b9b2e0b2SEd Tanous { 937b9b2e0b2SEd Tanous lastIndex = 0; 938b9b2e0b2SEd Tanous } 939b9b2e0b2SEd Tanous else 940b9b2e0b2SEd Tanous { 941b9b2e0b2SEd Tanous lastIndex += 1; 942b9b2e0b2SEd Tanous } 943b9b2e0b2SEd Tanous memberArray.push_back( 944b9b2e0b2SEd Tanous {{"@odata.id", "/redfish/v1/AccountService/Accounts/" + 945b9b2e0b2SEd Tanous path.substr(lastIndex)}}); 946b9b2e0b2SEd Tanous } 947b9b2e0b2SEd Tanous }, 948b9b2e0b2SEd Tanous "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user", 949b9b2e0b2SEd Tanous "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 950b9b2e0b2SEd Tanous } 95104ae99ecSEd Tanous void doPost(crow::Response& res, const crow::Request& req, 95204ae99ecSEd Tanous const std::vector<std::string>& params) override 95304ae99ecSEd Tanous { 95404ae99ecSEd Tanous auto asyncResp = std::make_shared<AsyncResp>(res); 95504ae99ecSEd Tanous 9569712f8acSEd Tanous std::string username; 9579712f8acSEd Tanous std::string password; 958a24526dcSEd Tanous std::optional<std::string> roleId("User"); 959a24526dcSEd Tanous std::optional<bool> enabled = true; 9609712f8acSEd Tanous if (!json_util::readJson(req, res, "UserName", username, "Password", 9619712f8acSEd Tanous password, "RoleId", roleId, "Enabled", 9629712f8acSEd Tanous enabled)) 96304ae99ecSEd Tanous { 96404ae99ecSEd Tanous return; 96504ae99ecSEd Tanous } 96604ae99ecSEd Tanous 96784e12cb7SAppaRao Puli std::string priv = getRoleIdFromPrivilege(*roleId); 96884e12cb7SAppaRao Puli if (priv.empty()) 96904ae99ecSEd Tanous { 970f12894f8SJason M. Bills messages::propertyValueNotInList(asyncResp->res, *roleId, "RoleId"); 97104ae99ecSEd Tanous return; 97204ae99ecSEd Tanous } 9739712f8acSEd Tanous roleId = priv; 97404ae99ecSEd Tanous 97504ae99ecSEd Tanous crow::connections::systemBus->async_method_call( 9769712f8acSEd Tanous [asyncResp, username, password{std::move(password)}]( 97704ae99ecSEd Tanous const boost::system::error_code ec) { 97804ae99ecSEd Tanous if (ec) 97904ae99ecSEd Tanous { 98004ae99ecSEd Tanous messages::resourceAlreadyExists( 981f12894f8SJason M. Bills asyncResp->res, "#ManagerAccount.v1_0_3.ManagerAccount", 982f12894f8SJason M. Bills "UserName", username); 98304ae99ecSEd Tanous return; 98404ae99ecSEd Tanous } 98504ae99ecSEd Tanous 98604ae99ecSEd Tanous if (!pamUpdatePassword(username, password)) 98704ae99ecSEd Tanous { 98804ae99ecSEd Tanous // At this point we have a user that's been created, but the 98904ae99ecSEd Tanous // password set failed. Something is wrong, so delete the 99004ae99ecSEd Tanous // user that we've already created 99104ae99ecSEd Tanous crow::connections::systemBus->async_method_call( 99204ae99ecSEd Tanous [asyncResp](const boost::system::error_code ec) { 99304ae99ecSEd Tanous if (ec) 99404ae99ecSEd Tanous { 995f12894f8SJason M. Bills messages::internalError(asyncResp->res); 99604ae99ecSEd Tanous return; 99704ae99ecSEd Tanous } 99804ae99ecSEd Tanous 999f12894f8SJason M. Bills messages::invalidObject(asyncResp->res, "Password"); 100004ae99ecSEd Tanous }, 100104ae99ecSEd Tanous "xyz.openbmc_project.User.Manager", 100204ae99ecSEd Tanous "/xyz/openbmc_project/user/" + username, 100304ae99ecSEd Tanous "xyz.openbmc_project.Object.Delete", "Delete"); 100404ae99ecSEd Tanous 100504ae99ecSEd Tanous BMCWEB_LOG_ERROR << "pamUpdatePassword Failed"; 100604ae99ecSEd Tanous return; 100704ae99ecSEd Tanous } 100804ae99ecSEd Tanous 1009f12894f8SJason M. Bills messages::created(asyncResp->res); 101004ae99ecSEd Tanous asyncResp->res.addHeader( 101104ae99ecSEd Tanous "Location", 101204ae99ecSEd Tanous "/redfish/v1/AccountService/Accounts/" + username); 101304ae99ecSEd Tanous }, 101404ae99ecSEd Tanous "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user", 10159712f8acSEd Tanous "xyz.openbmc_project.User.Manager", "CreateUser", username, 101604ae99ecSEd Tanous std::array<const char*, 4>{"ipmi", "redfish", "ssh", "web"}, 10179712f8acSEd Tanous *roleId, *enabled); 101804ae99ecSEd Tanous } 1019b9b2e0b2SEd Tanous }; 1020b9b2e0b2SEd Tanous 1021b9b2e0b2SEd Tanous class ManagerAccount : public Node 1022b9b2e0b2SEd Tanous { 1023b9b2e0b2SEd Tanous public: 1024b9b2e0b2SEd Tanous ManagerAccount(CrowApp& app) : 1025b9b2e0b2SEd Tanous Node(app, "/redfish/v1/AccountService/Accounts/<str>/", std::string()) 1026b9b2e0b2SEd Tanous { 1027b9b2e0b2SEd Tanous entityPrivileges = { 1028b9b2e0b2SEd Tanous {boost::beast::http::verb::get, 1029b9b2e0b2SEd Tanous {{"ConfigureUsers"}, {"ConfigureManager"}, {"ConfigureSelf"}}}, 1030b9b2e0b2SEd Tanous {boost::beast::http::verb::head, {{"Login"}}}, 1031b9b2e0b2SEd Tanous {boost::beast::http::verb::patch, {{"ConfigureUsers"}}}, 1032b9b2e0b2SEd Tanous {boost::beast::http::verb::put, {{"ConfigureUsers"}}}, 1033b9b2e0b2SEd Tanous {boost::beast::http::verb::delete_, {{"ConfigureUsers"}}}, 1034b9b2e0b2SEd Tanous {boost::beast::http::verb::post, {{"ConfigureUsers"}}}}; 1035b9b2e0b2SEd Tanous } 1036b9b2e0b2SEd Tanous 1037b9b2e0b2SEd Tanous private: 1038b9b2e0b2SEd Tanous void doGet(crow::Response& res, const crow::Request& req, 1039b9b2e0b2SEd Tanous const std::vector<std::string>& params) override 1040b9b2e0b2SEd Tanous { 10410f74e643SEd Tanous res.jsonValue = { 10420f74e643SEd Tanous {"@odata.context", 10430f74e643SEd Tanous "/redfish/v1/$metadata#ManagerAccount.ManagerAccount"}, 10440f74e643SEd Tanous {"@odata.type", "#ManagerAccount.v1_0_3.ManagerAccount"}, 10450f74e643SEd Tanous {"Name", "User Account"}, 10460f74e643SEd Tanous {"Description", "User Account"}, 10470f74e643SEd Tanous {"Password", nullptr}, 104884e12cb7SAppaRao Puli {"RoleId", "Administrator"}}; 10490f74e643SEd Tanous 1050b9b2e0b2SEd Tanous auto asyncResp = std::make_shared<AsyncResp>(res); 1051b9b2e0b2SEd Tanous 1052b9b2e0b2SEd Tanous if (params.size() != 1) 1053b9b2e0b2SEd Tanous { 1054f12894f8SJason M. Bills messages::internalError(asyncResp->res); 1055b9b2e0b2SEd Tanous return; 1056b9b2e0b2SEd Tanous } 1057b9b2e0b2SEd Tanous 1058b9b2e0b2SEd Tanous crow::connections::systemBus->async_method_call( 1059b9b2e0b2SEd Tanous [asyncResp, accountName{std::string(params[0])}]( 1060b9b2e0b2SEd Tanous const boost::system::error_code ec, 1061b9b2e0b2SEd Tanous const ManagedObjectType& users) { 1062b9b2e0b2SEd Tanous if (ec) 1063b9b2e0b2SEd Tanous { 1064f12894f8SJason M. Bills messages::internalError(asyncResp->res); 1065b9b2e0b2SEd Tanous return; 1066b9b2e0b2SEd Tanous } 106784e12cb7SAppaRao Puli auto userIt = users.begin(); 1068b9b2e0b2SEd Tanous 106984e12cb7SAppaRao Puli for (; userIt != users.end(); userIt++) 1070b9b2e0b2SEd Tanous { 107184e12cb7SAppaRao Puli if (boost::ends_with(userIt->first.str, "/" + accountName)) 1072b9b2e0b2SEd Tanous { 107384e12cb7SAppaRao Puli break; 1074b9b2e0b2SEd Tanous } 1075b9b2e0b2SEd Tanous } 107684e12cb7SAppaRao Puli if (userIt == users.end()) 1077b9b2e0b2SEd Tanous { 107884e12cb7SAppaRao Puli messages::resourceNotFound(asyncResp->res, "ManagerAccount", 107984e12cb7SAppaRao Puli accountName); 108084e12cb7SAppaRao Puli return; 108184e12cb7SAppaRao Puli } 108284e12cb7SAppaRao Puli for (const auto& interface : userIt->second) 108365b0dc32SEd Tanous { 108465b0dc32SEd Tanous if (interface.first == 108565b0dc32SEd Tanous "xyz.openbmc_project.User.Attributes") 108665b0dc32SEd Tanous { 108765b0dc32SEd Tanous for (const auto& property : interface.second) 108865b0dc32SEd Tanous { 108965b0dc32SEd Tanous if (property.first == "UserEnabled") 109065b0dc32SEd Tanous { 109165b0dc32SEd Tanous const bool* userEnabled = 1092abf2add6SEd Tanous std::get_if<bool>(&property.second); 109365b0dc32SEd Tanous if (userEnabled == nullptr) 109465b0dc32SEd Tanous { 109565b0dc32SEd Tanous BMCWEB_LOG_ERROR 109665b0dc32SEd Tanous << "UserEnabled wasn't a bool"; 109784e12cb7SAppaRao Puli messages::internalError(asyncResp->res); 109884e12cb7SAppaRao Puli return; 109965b0dc32SEd Tanous } 110065b0dc32SEd Tanous asyncResp->res.jsonValue["Enabled"] = 110165b0dc32SEd Tanous *userEnabled; 110265b0dc32SEd Tanous } 110365b0dc32SEd Tanous else if (property.first == 110465b0dc32SEd Tanous "UserLockedForFailedAttempt") 110565b0dc32SEd Tanous { 110665b0dc32SEd Tanous const bool* userLocked = 1107abf2add6SEd Tanous std::get_if<bool>(&property.second); 110865b0dc32SEd Tanous if (userLocked == nullptr) 110965b0dc32SEd Tanous { 111084e12cb7SAppaRao Puli BMCWEB_LOG_ERROR << "UserLockedForF" 111184e12cb7SAppaRao Puli "ailedAttempt " 111284e12cb7SAppaRao Puli "wasn't a bool"; 111384e12cb7SAppaRao Puli messages::internalError(asyncResp->res); 111484e12cb7SAppaRao Puli return; 111565b0dc32SEd Tanous } 111665b0dc32SEd Tanous asyncResp->res.jsonValue["Locked"] = 111765b0dc32SEd Tanous *userLocked; 111824c8542dSRatan Gupta asyncResp->res.jsonValue 111924c8542dSRatan Gupta ["Locked@Redfish.AllowableValues"] = { 11204d64ce34SGunnar Mills "false"}; 112165b0dc32SEd Tanous } 112284e12cb7SAppaRao Puli else if (property.first == "UserPrivilege") 112384e12cb7SAppaRao Puli { 112484e12cb7SAppaRao Puli const std::string* userRolePtr = 1125abf2add6SEd Tanous std::get_if<std::string>(&property.second); 112684e12cb7SAppaRao Puli if (userRolePtr == nullptr) 112784e12cb7SAppaRao Puli { 112884e12cb7SAppaRao Puli BMCWEB_LOG_ERROR 112984e12cb7SAppaRao Puli << "UserPrivilege wasn't a " 113084e12cb7SAppaRao Puli "string"; 113184e12cb7SAppaRao Puli messages::internalError(asyncResp->res); 113284e12cb7SAppaRao Puli return; 113384e12cb7SAppaRao Puli } 113484e12cb7SAppaRao Puli std::string priv = 113584e12cb7SAppaRao Puli getPrivilegeFromRoleId(*userRolePtr); 113684e12cb7SAppaRao Puli if (priv.empty()) 113784e12cb7SAppaRao Puli { 113884e12cb7SAppaRao Puli BMCWEB_LOG_ERROR << "Invalid user role"; 113984e12cb7SAppaRao Puli messages::internalError(asyncResp->res); 114084e12cb7SAppaRao Puli return; 114184e12cb7SAppaRao Puli } 114284e12cb7SAppaRao Puli asyncResp->res.jsonValue["RoleId"] = priv; 114384e12cb7SAppaRao Puli 114484e12cb7SAppaRao Puli asyncResp->res.jsonValue["Links"]["Role"] = { 114584e12cb7SAppaRao Puli {"@odata.id", "/redfish/v1/AccountService/" 114684e12cb7SAppaRao Puli "Roles/" + 114784e12cb7SAppaRao Puli priv}}; 114884e12cb7SAppaRao Puli } 114965b0dc32SEd Tanous } 115065b0dc32SEd Tanous } 115165b0dc32SEd Tanous } 115265b0dc32SEd Tanous 1153b9b2e0b2SEd Tanous asyncResp->res.jsonValue["@odata.id"] = 115484e12cb7SAppaRao Puli "/redfish/v1/AccountService/Accounts/" + accountName; 1155b9b2e0b2SEd Tanous asyncResp->res.jsonValue["Id"] = accountName; 1156b9b2e0b2SEd Tanous asyncResp->res.jsonValue["UserName"] = accountName; 1157b9b2e0b2SEd Tanous }, 1158b9b2e0b2SEd Tanous "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user", 1159b9b2e0b2SEd Tanous "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 1160b9b2e0b2SEd Tanous } 1161a840879dSEd Tanous 1162a840879dSEd Tanous void doPatch(crow::Response& res, const crow::Request& req, 1163a840879dSEd Tanous const std::vector<std::string>& params) override 1164a840879dSEd Tanous { 1165a840879dSEd Tanous auto asyncResp = std::make_shared<AsyncResp>(res); 1166a840879dSEd Tanous if (params.size() != 1) 1167a840879dSEd Tanous { 1168f12894f8SJason M. Bills messages::internalError(asyncResp->res); 1169a840879dSEd Tanous return; 1170a840879dSEd Tanous } 1171a840879dSEd Tanous 1172a24526dcSEd Tanous std::optional<std::string> newUserName; 1173a24526dcSEd Tanous std::optional<std::string> password; 1174a24526dcSEd Tanous std::optional<bool> enabled; 1175a24526dcSEd Tanous std::optional<std::string> roleId; 117624c8542dSRatan Gupta std::optional<bool> locked; 117784e12cb7SAppaRao Puli if (!json_util::readJson(req, res, "UserName", newUserName, "Password", 117824c8542dSRatan Gupta password, "RoleId", roleId, "Enabled", enabled, 117924c8542dSRatan Gupta "Locked", locked)) 1180a840879dSEd Tanous { 1181a840879dSEd Tanous return; 1182a840879dSEd Tanous } 1183a840879dSEd Tanous 118484e12cb7SAppaRao Puli const std::string& username = params[0]; 118584e12cb7SAppaRao Puli 118684e12cb7SAppaRao Puli if (!newUserName) 1187a840879dSEd Tanous { 118884e12cb7SAppaRao Puli // If the username isn't being updated, we can update the properties 118984e12cb7SAppaRao Puli // directly 119024c8542dSRatan Gupta updateUserProperties(asyncResp, username, password, enabled, roleId, 119124c8542dSRatan Gupta locked); 119284e12cb7SAppaRao Puli return; 119384e12cb7SAppaRao Puli } 119484e12cb7SAppaRao Puli else 119584e12cb7SAppaRao Puli { 119684e12cb7SAppaRao Puli crow::connections::systemBus->async_method_call( 119784e12cb7SAppaRao Puli [this, asyncResp, username, password(std::move(password)), 119884e12cb7SAppaRao Puli roleId(std::move(roleId)), enabled(std::move(enabled)), 119924c8542dSRatan Gupta newUser{std::string(*newUserName)}, locked(std::move(locked))]( 120084e12cb7SAppaRao Puli const boost::system::error_code ec) { 120184e12cb7SAppaRao Puli if (ec) 120284e12cb7SAppaRao Puli { 120384e12cb7SAppaRao Puli BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec; 1204a840879dSEd Tanous messages::resourceNotFound( 120584e12cb7SAppaRao Puli asyncResp->res, 120684e12cb7SAppaRao Puli "#ManagerAccount.v1_0_3.ManagerAccount", username); 1207a840879dSEd Tanous return; 1208a840879dSEd Tanous } 1209a840879dSEd Tanous 121084e12cb7SAppaRao Puli updateUserProperties(asyncResp, newUser, password, enabled, 121124c8542dSRatan Gupta roleId, locked); 121284e12cb7SAppaRao Puli }, 121384e12cb7SAppaRao Puli "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user", 121484e12cb7SAppaRao Puli "xyz.openbmc_project.User.Manager", "RenameUser", username, 121584e12cb7SAppaRao Puli *newUserName); 121684e12cb7SAppaRao Puli } 121784e12cb7SAppaRao Puli } 121884e12cb7SAppaRao Puli 121984e12cb7SAppaRao Puli void updateUserProperties(std::shared_ptr<AsyncResp> asyncResp, 122084e12cb7SAppaRao Puli const std::string& username, 1221a24526dcSEd Tanous std::optional<std::string> password, 1222a24526dcSEd Tanous std::optional<bool> enabled, 122324c8542dSRatan Gupta std::optional<std::string> roleId, 122424c8542dSRatan Gupta std::optional<bool> locked) 122584e12cb7SAppaRao Puli { 12269712f8acSEd Tanous if (password) 1227a840879dSEd Tanous { 12289712f8acSEd Tanous if (!pamUpdatePassword(username, *password)) 1229a840879dSEd Tanous { 1230a840879dSEd Tanous BMCWEB_LOG_ERROR << "pamUpdatePassword Failed"; 1231f12894f8SJason M. Bills messages::internalError(asyncResp->res); 1232a840879dSEd Tanous return; 1233a840879dSEd Tanous } 1234a840879dSEd Tanous } 1235a840879dSEd Tanous 123624c8542dSRatan Gupta std::string dbusObjectPath = "/xyz/openbmc_project/user/" + username; 123724c8542dSRatan Gupta dbus::utility::escapePathForDbus(dbusObjectPath); 123824c8542dSRatan Gupta 1239*22c33710SRatan Gupta dbus::utility::checkDbusPathExists( 124024c8542dSRatan Gupta dbusObjectPath, 124124c8542dSRatan Gupta [dbusObjectPath(std::move(dbusObjectPath)), username, 124224c8542dSRatan Gupta password(std::move(password)), roleId(std::move(roleId)), 124324c8542dSRatan Gupta enabled(std::move(enabled)), locked(std::move(locked)), 124424c8542dSRatan Gupta asyncResp{std::move(asyncResp)}](int rc) { 124524c8542dSRatan Gupta if (!rc) 124624c8542dSRatan Gupta { 124724c8542dSRatan Gupta messages::invalidObject(asyncResp->res, username.c_str()); 124824c8542dSRatan Gupta return; 124924c8542dSRatan Gupta } 12509712f8acSEd Tanous if (enabled) 1251a840879dSEd Tanous { 1252a840879dSEd Tanous crow::connections::systemBus->async_method_call( 1253a840879dSEd Tanous [asyncResp](const boost::system::error_code ec) { 1254a840879dSEd Tanous if (ec) 1255a840879dSEd Tanous { 125624c8542dSRatan Gupta BMCWEB_LOG_ERROR << "D-Bus responses error: " 125724c8542dSRatan Gupta << ec; 1258f12894f8SJason M. Bills messages::internalError(asyncResp->res); 1259a840879dSEd Tanous return; 1260a840879dSEd Tanous } 126184e12cb7SAppaRao Puli messages::success(asyncResp->res); 126284e12cb7SAppaRao Puli return; 126384e12cb7SAppaRao Puli }, 126484e12cb7SAppaRao Puli "xyz.openbmc_project.User.Manager", 126524c8542dSRatan Gupta dbusObjectPath.c_str(), 126684e12cb7SAppaRao Puli "org.freedesktop.DBus.Properties", "Set", 126784e12cb7SAppaRao Puli "xyz.openbmc_project.User.Attributes", "UserEnabled", 1268abf2add6SEd Tanous std::variant<bool>{*enabled}); 126984e12cb7SAppaRao Puli } 127084e12cb7SAppaRao Puli 127184e12cb7SAppaRao Puli if (roleId) 127284e12cb7SAppaRao Puli { 127384e12cb7SAppaRao Puli std::string priv = getRoleIdFromPrivilege(*roleId); 127484e12cb7SAppaRao Puli if (priv.empty()) 127584e12cb7SAppaRao Puli { 127624c8542dSRatan Gupta messages::propertyValueNotInList(asyncResp->res, 127724c8542dSRatan Gupta *roleId, "RoleId"); 127884e12cb7SAppaRao Puli return; 127984e12cb7SAppaRao Puli } 128084e12cb7SAppaRao Puli 128184e12cb7SAppaRao Puli crow::connections::systemBus->async_method_call( 128284e12cb7SAppaRao Puli [asyncResp](const boost::system::error_code ec) { 128384e12cb7SAppaRao Puli if (ec) 128484e12cb7SAppaRao Puli { 128524c8542dSRatan Gupta BMCWEB_LOG_ERROR << "D-Bus responses error: " 128624c8542dSRatan Gupta << ec; 128784e12cb7SAppaRao Puli messages::internalError(asyncResp->res); 128884e12cb7SAppaRao Puli return; 128984e12cb7SAppaRao Puli } 1290f12894f8SJason M. Bills messages::success(asyncResp->res); 1291a840879dSEd Tanous }, 1292a840879dSEd Tanous "xyz.openbmc_project.User.Manager", 129324c8542dSRatan Gupta dbusObjectPath.c_str(), 1294a840879dSEd Tanous "org.freedesktop.DBus.Properties", "Set", 129584e12cb7SAppaRao Puli "xyz.openbmc_project.User.Attributes", "UserPrivilege", 1296abf2add6SEd Tanous std::variant<std::string>{priv}); 1297a840879dSEd Tanous } 129824c8542dSRatan Gupta 129924c8542dSRatan Gupta if (locked) 130024c8542dSRatan Gupta { 130124c8542dSRatan Gupta // admin can unlock the account which is locked by 130224c8542dSRatan Gupta // successive authentication failures but admin should not 130324c8542dSRatan Gupta // be allowed to lock an account. 130424c8542dSRatan Gupta if (*locked) 130524c8542dSRatan Gupta { 130624c8542dSRatan Gupta messages::propertyValueNotInList(asyncResp->res, "true", 130724c8542dSRatan Gupta "Locked"); 130824c8542dSRatan Gupta return; 130924c8542dSRatan Gupta } 131024c8542dSRatan Gupta 131124c8542dSRatan Gupta crow::connections::systemBus->async_method_call( 131224c8542dSRatan Gupta [asyncResp](const boost::system::error_code ec) { 131324c8542dSRatan Gupta if (ec) 131424c8542dSRatan Gupta { 131524c8542dSRatan Gupta BMCWEB_LOG_ERROR << "D-Bus responses error: " 131624c8542dSRatan Gupta << ec; 131724c8542dSRatan Gupta messages::internalError(asyncResp->res); 131824c8542dSRatan Gupta return; 131924c8542dSRatan Gupta } 132024c8542dSRatan Gupta messages::success(asyncResp->res); 132124c8542dSRatan Gupta return; 132224c8542dSRatan Gupta }, 132324c8542dSRatan Gupta "xyz.openbmc_project.User.Manager", 132424c8542dSRatan Gupta dbusObjectPath.c_str(), 132524c8542dSRatan Gupta "org.freedesktop.DBus.Properties", "Set", 132624c8542dSRatan Gupta "xyz.openbmc_project.User.Attributes", 132724c8542dSRatan Gupta "UserLockedForFailedAttempt", 132824c8542dSRatan Gupta sdbusplus::message::variant<bool>{*locked}); 132924c8542dSRatan Gupta } 133024c8542dSRatan Gupta }); 1331a840879dSEd Tanous } 133206e086d9SEd Tanous 133306e086d9SEd Tanous void doDelete(crow::Response& res, const crow::Request& req, 133406e086d9SEd Tanous const std::vector<std::string>& params) override 133506e086d9SEd Tanous { 133606e086d9SEd Tanous auto asyncResp = std::make_shared<AsyncResp>(res); 133706e086d9SEd Tanous 133806e086d9SEd Tanous if (params.size() != 1) 133906e086d9SEd Tanous { 1340f12894f8SJason M. Bills messages::internalError(asyncResp->res); 134106e086d9SEd Tanous return; 134206e086d9SEd Tanous } 134306e086d9SEd Tanous 134406e086d9SEd Tanous const std::string userPath = "/xyz/openbmc_project/user/" + params[0]; 134506e086d9SEd Tanous 134606e086d9SEd Tanous crow::connections::systemBus->async_method_call( 134706e086d9SEd Tanous [asyncResp, username{std::move(params[0])}]( 134806e086d9SEd Tanous const boost::system::error_code ec) { 134906e086d9SEd Tanous if (ec) 135006e086d9SEd Tanous { 135106e086d9SEd Tanous messages::resourceNotFound( 1352f12894f8SJason M. Bills asyncResp->res, "#ManagerAccount.v1_0_3.ManagerAccount", 1353f12894f8SJason M. Bills username); 135406e086d9SEd Tanous return; 135506e086d9SEd Tanous } 135606e086d9SEd Tanous 1357f12894f8SJason M. Bills messages::accountRemoved(asyncResp->res); 135806e086d9SEd Tanous }, 135906e086d9SEd Tanous "xyz.openbmc_project.User.Manager", userPath, 136006e086d9SEd Tanous "xyz.openbmc_project.Object.Delete", "Delete"); 136106e086d9SEd Tanous } 136284e12cb7SAppaRao Puli }; 136388d16c9aSLewanczyk, Dawid 136488d16c9aSLewanczyk, Dawid } // namespace redfish 1365