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"; 113ab828d7cSRatan Gupta json_response[ldapType] = { 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 }; 1286973a582SRatan Gupta } 1296973a582SRatan Gupta 1306973a582SRatan Gupta /** 1316973a582SRatan Gupta * Function that retrieves all properties for LDAP config object 1326973a582SRatan Gupta * into JSON 1336973a582SRatan Gupta */ 1346973a582SRatan Gupta template <typename CallbackFunc> 1356973a582SRatan Gupta inline void getLDAPConfigData(const std::string& ldapType, 1366973a582SRatan Gupta CallbackFunc&& callback) 1376973a582SRatan Gupta { 1386973a582SRatan Gupta auto getConfig = [callback, 1396973a582SRatan Gupta ldapType](const boost::system::error_code error_code, 1406973a582SRatan Gupta const ManagedObjectType& ldapObjects) { 1416973a582SRatan Gupta LDAPConfigData confData{}; 1426973a582SRatan Gupta if (error_code) 1436973a582SRatan Gupta { 144ab828d7cSRatan Gupta callback(false, confData, ldapType); 1456973a582SRatan Gupta BMCWEB_LOG_ERROR << "D-Bus responses error: " << error_code; 1466973a582SRatan Gupta return; 1476973a582SRatan Gupta } 148ab828d7cSRatan Gupta 149ab828d7cSRatan Gupta std::string ldapDbusType; 150ab828d7cSRatan Gupta if (ldapType == "LDAP") 151ab828d7cSRatan Gupta { 152ab828d7cSRatan Gupta ldapDbusType = "xyz.openbmc_project.User.Ldap.Config.Type.OpenLdap"; 153ab828d7cSRatan Gupta } 154ab828d7cSRatan Gupta else if (ldapType == "ActiveDirectory") 155ab828d7cSRatan Gupta { 156ab828d7cSRatan Gupta ldapDbusType = "xyz.openbmc_project.User.Ldap.Config.Type." 157ab828d7cSRatan Gupta "ActiveDirectory"; 158ab828d7cSRatan Gupta } 159ab828d7cSRatan Gupta else 160ab828d7cSRatan Gupta { 161ab828d7cSRatan Gupta BMCWEB_LOG_ERROR << "Can't get the DbusType for the given type=" 162ab828d7cSRatan Gupta << ldapType; 163ab828d7cSRatan Gupta callback(false, confData, ldapType); 164ab828d7cSRatan Gupta return; 165ab828d7cSRatan Gupta } 166ab828d7cSRatan Gupta 167ab828d7cSRatan Gupta std::string ldapEnableInterfaceStr = ldapEnableInterface; 168ab828d7cSRatan Gupta std::string ldapConfigInterfaceStr = ldapConfigInterface; 169ab828d7cSRatan Gupta 1706973a582SRatan Gupta for (const auto& object : ldapObjects) 1716973a582SRatan Gupta { 172ab828d7cSRatan Gupta // let's find the object whose ldap type is equal to the given type 173ab828d7cSRatan Gupta auto intfit = object.second.find(ldapConfigInterfaceStr); 174ab828d7cSRatan Gupta if (intfit == object.second.end()) 1756973a582SRatan Gupta { 176ab828d7cSRatan Gupta continue; 177ab828d7cSRatan Gupta } 178ab828d7cSRatan Gupta auto propit = intfit->second.find("LDAPType"); 179ab828d7cSRatan Gupta if (propit == intfit->second.end()) 180ab828d7cSRatan Gupta { 181ab828d7cSRatan Gupta continue; 182ab828d7cSRatan Gupta } 183ab828d7cSRatan Gupta 184ab828d7cSRatan Gupta const std::string* value = 185ab828d7cSRatan Gupta std::get_if<std::string>(&(propit->second)); 186ab828d7cSRatan Gupta if (value == nullptr || (*value) != ldapDbusType) 187ab828d7cSRatan Gupta { 188ab828d7cSRatan Gupta 189ab828d7cSRatan Gupta // this is not the interested configuration, 190ab828d7cSRatan Gupta // let's move on to the other configuration. 191ab828d7cSRatan Gupta continue; 192ab828d7cSRatan Gupta } 193ab828d7cSRatan Gupta else 194ab828d7cSRatan Gupta { 195ab828d7cSRatan Gupta confData.serverType = *value; 196ab828d7cSRatan Gupta } 197ab828d7cSRatan Gupta 1986973a582SRatan Gupta for (const auto& interface : object.second) 1996973a582SRatan Gupta { 2006973a582SRatan Gupta if (interface.first == ldapEnableInterfaceStr) 2016973a582SRatan Gupta { 2026973a582SRatan Gupta // rest of the properties are string. 2036973a582SRatan Gupta for (const auto& property : interface.second) 2046973a582SRatan Gupta { 2056973a582SRatan Gupta if (property.first == "Enabled") 2066973a582SRatan Gupta { 2076973a582SRatan Gupta const bool* value = 2086973a582SRatan Gupta std::get_if<bool>(&property.second); 2096973a582SRatan Gupta if (value == nullptr) 2106973a582SRatan Gupta { 2116973a582SRatan Gupta continue; 2126973a582SRatan Gupta } 2136973a582SRatan Gupta confData.serviceEnabled = *value; 2146973a582SRatan Gupta break; 2156973a582SRatan Gupta } 2166973a582SRatan Gupta } 2176973a582SRatan Gupta } 2186973a582SRatan Gupta else if (interface.first == ldapConfigInterfaceStr) 2196973a582SRatan Gupta { 2206973a582SRatan Gupta 2216973a582SRatan Gupta for (const auto& property : interface.second) 2226973a582SRatan Gupta { 2236973a582SRatan Gupta const std::string* value = 2246973a582SRatan Gupta std::get_if<std::string>(&property.second); 2256973a582SRatan Gupta if (value == nullptr) 2266973a582SRatan Gupta { 2276973a582SRatan Gupta continue; 2286973a582SRatan Gupta } 2296973a582SRatan Gupta if (property.first == "LDAPServerURI") 2306973a582SRatan Gupta { 2316973a582SRatan Gupta confData.uri = *value; 2326973a582SRatan Gupta } 2336973a582SRatan Gupta else if (property.first == "LDAPBindDN") 2346973a582SRatan Gupta { 2356973a582SRatan Gupta confData.bindDN = *value; 2366973a582SRatan Gupta } 2376973a582SRatan Gupta else if (property.first == "LDAPBaseDN") 2386973a582SRatan Gupta { 2396973a582SRatan Gupta confData.baseDN = *value; 2406973a582SRatan Gupta } 2416973a582SRatan Gupta else if (property.first == "LDAPSearchScope") 2426973a582SRatan Gupta { 2436973a582SRatan Gupta confData.searchScope = *value; 2446973a582SRatan Gupta } 2456973a582SRatan Gupta else if (property.first == "GroupNameAttribute") 2466973a582SRatan Gupta { 2476973a582SRatan Gupta confData.groupAttribute = *value; 2486973a582SRatan Gupta } 2496973a582SRatan Gupta else if (property.first == "UserNameAttribute") 2506973a582SRatan Gupta { 2516973a582SRatan Gupta confData.userNameAttribute = *value; 2526973a582SRatan Gupta } 2536973a582SRatan Gupta } 2546973a582SRatan Gupta } 2556973a582SRatan Gupta } 256ab828d7cSRatan Gupta if (confData.serverType == ldapDbusType) 257ab828d7cSRatan Gupta { 258ab828d7cSRatan Gupta callback(true, confData, ldapType); 2596973a582SRatan Gupta break; 2606973a582SRatan Gupta } 2616973a582SRatan Gupta } 2626973a582SRatan Gupta }; 263ab828d7cSRatan Gupta auto getServiceName = [callback, ldapType, getConfig(std::move(getConfig))]( 2646973a582SRatan Gupta const boost::system::error_code ec, 2656973a582SRatan Gupta const GetObjectType& resp) { 2666973a582SRatan Gupta LDAPConfigData confData{}; 2676973a582SRatan Gupta if (ec || resp.empty()) 2686973a582SRatan Gupta { 2696973a582SRatan Gupta BMCWEB_LOG_ERROR 2706973a582SRatan Gupta << "DBUS response error during getting of service name: " << ec; 271ab828d7cSRatan Gupta callback(false, confData, ldapType); 2726973a582SRatan Gupta return; 2736973a582SRatan Gupta } 2746973a582SRatan Gupta std::string service = resp.begin()->first; 2756973a582SRatan Gupta crow::connections::systemBus->async_method_call( 2766973a582SRatan Gupta std::move(getConfig), service, ldapRootObject, dbusObjManagerIntf, 2776973a582SRatan Gupta "GetManagedObjects"); 2786973a582SRatan Gupta }; 2796973a582SRatan Gupta 2806973a582SRatan Gupta const std::array<std::string, 2> interfaces = {ldapEnableInterface, 2816973a582SRatan Gupta ldapConfigInterface}; 2826973a582SRatan Gupta 2836973a582SRatan Gupta crow::connections::systemBus->async_method_call( 2846973a582SRatan Gupta std::move(getServiceName), mapperBusName, mapperObjectPath, mapperIntf, 2856973a582SRatan Gupta "GetObject", ldapConfigObject, interfaces); 2866973a582SRatan Gupta } 2876973a582SRatan Gupta 2881abe55efSEd Tanous class AccountService : public Node 2891abe55efSEd Tanous { 29088d16c9aSLewanczyk, Dawid public: 2911abe55efSEd Tanous AccountService(CrowApp& app) : Node(app, "/redfish/v1/AccountService/") 2921abe55efSEd Tanous { 2933ebd75f7SEd Tanous entityPrivileges = { 2944b1b8683SBorawski.Lukasz {boost::beast::http::verb::get, 2954b1b8683SBorawski.Lukasz {{"ConfigureUsers"}, {"ConfigureManager"}}}, 296e0d918bcSEd Tanous {boost::beast::http::verb::head, {{"Login"}}}, 297e0d918bcSEd Tanous {boost::beast::http::verb::patch, {{"ConfigureUsers"}}}, 298e0d918bcSEd Tanous {boost::beast::http::verb::put, {{"ConfigureUsers"}}}, 299e0d918bcSEd Tanous {boost::beast::http::verb::delete_, {{"ConfigureUsers"}}}, 300e0d918bcSEd Tanous {boost::beast::http::verb::post, {{"ConfigureUsers"}}}}; 30188d16c9aSLewanczyk, Dawid } 30288d16c9aSLewanczyk, Dawid 30388d16c9aSLewanczyk, Dawid private: 3048a07d286SRatan Gupta /** 3058a07d286SRatan Gupta * @brief parses the authentication section under the LDAP 3068a07d286SRatan Gupta * @param input JSON data 3078a07d286SRatan Gupta * @param asyncResp pointer to the JSON response 3088a07d286SRatan Gupta * @param userName userName to be filled from the given JSON. 3098a07d286SRatan Gupta * @param password password to be filled from the given JSON. 3108a07d286SRatan Gupta */ 3118a07d286SRatan Gupta void 3128a07d286SRatan Gupta parseLDAPAuthenticationJson(nlohmann::json input, 3138a07d286SRatan Gupta const std::shared_ptr<AsyncResp>& asyncResp, 3148a07d286SRatan Gupta std::optional<std::string>& username, 3158a07d286SRatan Gupta std::optional<std::string>& password) 3168a07d286SRatan Gupta { 3178a07d286SRatan Gupta std::optional<std::string> authType; 3188a07d286SRatan Gupta 3198a07d286SRatan Gupta if (!json_util::readJson(input, asyncResp->res, "AuthenticationType", 3208a07d286SRatan Gupta authType, "Username", username, "Password", 3218a07d286SRatan Gupta password)) 3228a07d286SRatan Gupta { 3238a07d286SRatan Gupta return; 3248a07d286SRatan Gupta } 3258a07d286SRatan Gupta if (!authType) 3268a07d286SRatan Gupta { 3278a07d286SRatan Gupta return; 3288a07d286SRatan Gupta } 3298a07d286SRatan Gupta if (*authType != "UsernameAndPassword") 3308a07d286SRatan Gupta { 3318a07d286SRatan Gupta messages::propertyValueNotInList(asyncResp->res, *authType, 3328a07d286SRatan Gupta "AuthenticationType"); 3338a07d286SRatan Gupta return; 3348a07d286SRatan Gupta } 3358a07d286SRatan Gupta } 3368a07d286SRatan Gupta /** 3378a07d286SRatan Gupta * @brief parses the LDAPService section under the LDAP 3388a07d286SRatan Gupta * @param input JSON data 3398a07d286SRatan Gupta * @param asyncResp pointer to the JSON response 3408a07d286SRatan Gupta * @param baseDNList baseDN to be filled from the given JSON. 3418a07d286SRatan Gupta * @param userNameAttribute userName to be filled from the given JSON. 3428a07d286SRatan Gupta * @param groupaAttribute password to be filled from the given JSON. 3438a07d286SRatan Gupta */ 3448a07d286SRatan Gupta 3458a07d286SRatan Gupta void parseLDAPServiceJson( 3468a07d286SRatan Gupta nlohmann::json input, const std::shared_ptr<AsyncResp>& asyncResp, 3478a07d286SRatan Gupta std::optional<std::vector<std::string>>& baseDNList, 3488a07d286SRatan Gupta std::optional<std::string>& userNameAttribute, 3498a07d286SRatan Gupta std::optional<std::string>& groupsAttribute) 3508a07d286SRatan Gupta { 3518a07d286SRatan Gupta std::optional<nlohmann::json> searchSettings; 3528a07d286SRatan Gupta 3538a07d286SRatan Gupta if (!json_util::readJson(input, asyncResp->res, "SearchSettings", 3548a07d286SRatan Gupta searchSettings)) 3558a07d286SRatan Gupta { 3568a07d286SRatan Gupta return; 3578a07d286SRatan Gupta } 3588a07d286SRatan Gupta if (!searchSettings) 3598a07d286SRatan Gupta { 3608a07d286SRatan Gupta return; 3618a07d286SRatan Gupta } 3628a07d286SRatan Gupta if (!json_util::readJson(*searchSettings, asyncResp->res, 3638a07d286SRatan Gupta "BaseDistinguishedNames", baseDNList, 3648a07d286SRatan Gupta "UsernameAttribute", userNameAttribute, 3658a07d286SRatan Gupta "GroupsAttribute", groupsAttribute)) 3668a07d286SRatan Gupta { 3678a07d286SRatan Gupta return; 3688a07d286SRatan Gupta } 3698a07d286SRatan Gupta } 3708a07d286SRatan Gupta /** 3718a07d286SRatan Gupta * @brief updates the LDAP server address and updates the 3728a07d286SRatan Gupta json response with the new value. 3738a07d286SRatan Gupta * @param serviceAddressList address to be updated. 3748a07d286SRatan Gupta * @param asyncResp pointer to the JSON response 3758a07d286SRatan Gupta * @param ldapServerElementName Type of LDAP 3768a07d286SRatan Gupta server(openLDAP/ActiveDirectory) 3778a07d286SRatan Gupta */ 3788a07d286SRatan Gupta 3798a07d286SRatan Gupta void handleServiceAddressPatch( 3808a07d286SRatan Gupta const std::vector<std::string>& serviceAddressList, 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, ldapServerElementName, 3878a07d286SRatan Gupta serviceAddressList](const boost::system::error_code ec) { 3888a07d286SRatan Gupta if (ec) 3898a07d286SRatan Gupta { 3908a07d286SRatan Gupta BMCWEB_LOG_DEBUG 3918a07d286SRatan Gupta << "Error Occured in updating the service address"; 3928a07d286SRatan Gupta messages::internalError(asyncResp->res); 3938a07d286SRatan Gupta return; 3948a07d286SRatan Gupta } 3958a07d286SRatan Gupta std::vector<std::string> modifiedserviceAddressList = { 3968a07d286SRatan Gupta serviceAddressList.front()}; 3978a07d286SRatan Gupta asyncResp->res 3988a07d286SRatan Gupta .jsonValue[ldapServerElementName]["ServiceAddresses"] = 3998a07d286SRatan Gupta modifiedserviceAddressList; 4008a07d286SRatan Gupta if ((serviceAddressList).size() > 1) 4018a07d286SRatan Gupta { 4028a07d286SRatan Gupta messages::propertyValueModified(asyncResp->res, 4038a07d286SRatan Gupta "ServiceAddresses", 4048a07d286SRatan Gupta serviceAddressList.front()); 4058a07d286SRatan Gupta } 4068a07d286SRatan Gupta BMCWEB_LOG_DEBUG << "Updated the service address"; 4078a07d286SRatan Gupta }, 4088a07d286SRatan Gupta ldapDbusService, ldapConfigObject, propertyInterface, "Set", 4098a07d286SRatan Gupta ldapConfigInterface, "LDAPServerURI", 4108a07d286SRatan Gupta std::variant<std::string>(serviceAddressList.front())); 4118a07d286SRatan Gupta } 4128a07d286SRatan Gupta /** 4138a07d286SRatan Gupta * @brief updates the LDAP Bind DN and updates the 4148a07d286SRatan Gupta json response with the new value. 4158a07d286SRatan Gupta * @param username name of the user which needs to be updated. 4168a07d286SRatan Gupta * @param asyncResp pointer to the JSON response 4178a07d286SRatan Gupta * @param ldapServerElementName Type of LDAP 4188a07d286SRatan Gupta server(openLDAP/ActiveDirectory) 4198a07d286SRatan Gupta */ 4208a07d286SRatan Gupta 4218a07d286SRatan Gupta void handleUserNamePatch(const std::string& username, 4228a07d286SRatan Gupta const std::shared_ptr<AsyncResp>& asyncResp, 4238a07d286SRatan Gupta const std::string& ldapServerElementName, 4248a07d286SRatan Gupta const std::string& ldapConfigObject) 4258a07d286SRatan Gupta { 4268a07d286SRatan Gupta crow::connections::systemBus->async_method_call( 4278a07d286SRatan Gupta [asyncResp, username, 4288a07d286SRatan Gupta ldapServerElementName](const boost::system::error_code ec) { 4298a07d286SRatan Gupta if (ec) 4308a07d286SRatan Gupta { 4318a07d286SRatan Gupta BMCWEB_LOG_DEBUG 4328a07d286SRatan Gupta << "Error occured in updating the username"; 4338a07d286SRatan Gupta messages::internalError(asyncResp->res); 4348a07d286SRatan Gupta return; 4358a07d286SRatan Gupta } 4368a07d286SRatan Gupta asyncResp->res.jsonValue[ldapServerElementName] 4378a07d286SRatan Gupta ["Authentication"]["Username"] = 4388a07d286SRatan Gupta username; 4398a07d286SRatan Gupta BMCWEB_LOG_DEBUG << "Updated the username"; 4408a07d286SRatan Gupta }, 4418a07d286SRatan Gupta ldapDbusService, ldapConfigObject, propertyInterface, "Set", 4428a07d286SRatan Gupta ldapConfigInterface, "LDAPBindDN", 4438a07d286SRatan Gupta std::variant<std::string>(username)); 4448a07d286SRatan Gupta } 4458a07d286SRatan Gupta 4468a07d286SRatan Gupta /** 4478a07d286SRatan Gupta * @brief updates the LDAP password 4488a07d286SRatan Gupta * @param password : ldap password which needs to be updated. 4498a07d286SRatan Gupta * @param asyncResp pointer to the JSON response 4508a07d286SRatan Gupta * @param ldapServerElementName Type of LDAP 4518a07d286SRatan Gupta * server(openLDAP/ActiveDirectory) 4528a07d286SRatan Gupta */ 4538a07d286SRatan Gupta 4548a07d286SRatan Gupta void handlePasswordPatch(const std::string& password, 4558a07d286SRatan Gupta const std::shared_ptr<AsyncResp>& asyncResp, 4568a07d286SRatan Gupta const std::string& ldapServerElementName, 4578a07d286SRatan Gupta const std::string& ldapConfigObject) 4588a07d286SRatan Gupta { 4598a07d286SRatan Gupta crow::connections::systemBus->async_method_call( 4608a07d286SRatan Gupta [asyncResp, password, 4618a07d286SRatan Gupta ldapServerElementName](const boost::system::error_code ec) { 4628a07d286SRatan Gupta if (ec) 4638a07d286SRatan Gupta { 4648a07d286SRatan Gupta BMCWEB_LOG_DEBUG 4658a07d286SRatan Gupta << "Error occured in updating the password"; 4668a07d286SRatan Gupta messages::internalError(asyncResp->res); 4678a07d286SRatan Gupta return; 4688a07d286SRatan Gupta } 4698a07d286SRatan Gupta asyncResp->res.jsonValue[ldapServerElementName] 4708a07d286SRatan Gupta ["Authentication"]["Password"] = ""; 4718a07d286SRatan Gupta BMCWEB_LOG_DEBUG << "Updated the password"; 4728a07d286SRatan Gupta }, 4738a07d286SRatan Gupta ldapDbusService, ldapConfigObject, propertyInterface, "Set", 4748a07d286SRatan Gupta ldapConfigInterface, "LDAPBindDNPassword", 4758a07d286SRatan Gupta std::variant<std::string>(password)); 4768a07d286SRatan Gupta } 4778a07d286SRatan Gupta 4788a07d286SRatan Gupta /** 4798a07d286SRatan Gupta * @brief updates the LDAP BaseDN and updates the 4808a07d286SRatan Gupta json response with the new value. 4818a07d286SRatan Gupta * @param baseDNList baseDN list which needs to be updated. 4828a07d286SRatan Gupta * @param asyncResp pointer to the JSON response 4838a07d286SRatan Gupta * @param ldapServerElementName Type of LDAP 4848a07d286SRatan Gupta server(openLDAP/ActiveDirectory) 4858a07d286SRatan Gupta */ 4868a07d286SRatan Gupta 4878a07d286SRatan Gupta void handleBaseDNPatch(const std::vector<std::string>& baseDNList, 4888a07d286SRatan Gupta const std::shared_ptr<AsyncResp>& asyncResp, 4898a07d286SRatan Gupta const std::string& ldapServerElementName, 4908a07d286SRatan Gupta const std::string& ldapConfigObject) 4918a07d286SRatan Gupta { 4928a07d286SRatan Gupta crow::connections::systemBus->async_method_call( 4938a07d286SRatan Gupta [asyncResp, baseDNList, 4948a07d286SRatan Gupta ldapServerElementName](const boost::system::error_code ec) { 4958a07d286SRatan Gupta if (ec) 4968a07d286SRatan Gupta { 4978a07d286SRatan Gupta BMCWEB_LOG_DEBUG << "Error Occured in Updating the base DN"; 4988a07d286SRatan Gupta messages::internalError(asyncResp->res); 4998a07d286SRatan Gupta return; 5008a07d286SRatan Gupta } 5018a07d286SRatan Gupta auto& serverTypeJson = 5028a07d286SRatan Gupta asyncResp->res.jsonValue[ldapServerElementName]; 5038a07d286SRatan Gupta auto& searchSettingsJson = 5048a07d286SRatan Gupta serverTypeJson["LDAPService"]["SearchSettings"]; 5058a07d286SRatan Gupta std::vector<std::string> modifiedBaseDNList = { 5068a07d286SRatan Gupta baseDNList.front()}; 5078a07d286SRatan Gupta searchSettingsJson["BaseDistinguishedNames"] = 5088a07d286SRatan Gupta modifiedBaseDNList; 5098a07d286SRatan Gupta if (baseDNList.size() > 1) 5108a07d286SRatan Gupta { 5118a07d286SRatan Gupta messages::propertyValueModified(asyncResp->res, 5128a07d286SRatan Gupta "BaseDistinguishedNames", 5138a07d286SRatan Gupta baseDNList.front()); 5148a07d286SRatan Gupta } 5158a07d286SRatan Gupta BMCWEB_LOG_DEBUG << "Updated the base DN"; 5168a07d286SRatan Gupta }, 5178a07d286SRatan Gupta ldapDbusService, ldapConfigObject, propertyInterface, "Set", 5188a07d286SRatan Gupta ldapConfigInterface, "LDAPBaseDN", 5198a07d286SRatan Gupta std::variant<std::string>(baseDNList.front())); 5208a07d286SRatan Gupta } 5218a07d286SRatan Gupta /** 5228a07d286SRatan Gupta * @brief updates the LDAP user name attribute and updates the 5238a07d286SRatan Gupta json response with the new value. 5248a07d286SRatan Gupta * @param userNameAttribute attribute to be updated. 5258a07d286SRatan Gupta * @param asyncResp pointer to the JSON response 5268a07d286SRatan Gupta * @param ldapServerElementName Type of LDAP 5278a07d286SRatan Gupta server(openLDAP/ActiveDirectory) 5288a07d286SRatan Gupta */ 5298a07d286SRatan Gupta 5308a07d286SRatan Gupta void handleUserNameAttrPatch(const std::string& userNameAttribute, 5318a07d286SRatan Gupta const std::shared_ptr<AsyncResp>& asyncResp, 5328a07d286SRatan Gupta const std::string& ldapServerElementName, 5338a07d286SRatan Gupta const std::string& ldapConfigObject) 5348a07d286SRatan Gupta { 5358a07d286SRatan Gupta crow::connections::systemBus->async_method_call( 5368a07d286SRatan Gupta [asyncResp, userNameAttribute, 5378a07d286SRatan Gupta ldapServerElementName](const boost::system::error_code ec) { 5388a07d286SRatan Gupta if (ec) 5398a07d286SRatan Gupta { 5408a07d286SRatan Gupta BMCWEB_LOG_DEBUG << "Error Occured in Updating the " 5418a07d286SRatan Gupta "username attribute"; 5428a07d286SRatan Gupta messages::internalError(asyncResp->res); 5438a07d286SRatan Gupta return; 5448a07d286SRatan Gupta } 5458a07d286SRatan Gupta auto& serverTypeJson = 5468a07d286SRatan Gupta asyncResp->res.jsonValue[ldapServerElementName]; 5478a07d286SRatan Gupta auto& searchSettingsJson = 5488a07d286SRatan Gupta serverTypeJson["LDAPService"]["SearchSettings"]; 5498a07d286SRatan Gupta searchSettingsJson["UsernameAttribute"] = userNameAttribute; 5508a07d286SRatan Gupta BMCWEB_LOG_DEBUG << "Updated the user name attr."; 5518a07d286SRatan Gupta }, 5528a07d286SRatan Gupta ldapDbusService, ldapConfigObject, propertyInterface, "Set", 5538a07d286SRatan Gupta ldapConfigInterface, "UserNameAttribute", 5548a07d286SRatan Gupta std::variant<std::string>(userNameAttribute)); 5558a07d286SRatan Gupta } 5568a07d286SRatan Gupta /** 5578a07d286SRatan Gupta * @brief updates the LDAP group attribute and updates the 5588a07d286SRatan Gupta json response with the new value. 5598a07d286SRatan Gupta * @param groupsAttribute attribute to be updated. 5608a07d286SRatan Gupta * @param asyncResp pointer to the JSON response 5618a07d286SRatan Gupta * @param ldapServerElementName Type of LDAP 5628a07d286SRatan Gupta server(openLDAP/ActiveDirectory) 5638a07d286SRatan Gupta */ 5648a07d286SRatan Gupta 5658a07d286SRatan Gupta void handleGroupNameAttrPatch(const std::string& groupsAttribute, 5668a07d286SRatan Gupta const std::shared_ptr<AsyncResp>& asyncResp, 5678a07d286SRatan Gupta const std::string& ldapServerElementName, 5688a07d286SRatan Gupta const std::string& ldapConfigObject) 5698a07d286SRatan Gupta { 5708a07d286SRatan Gupta crow::connections::systemBus->async_method_call( 5718a07d286SRatan Gupta [asyncResp, groupsAttribute, 5728a07d286SRatan Gupta ldapServerElementName](const boost::system::error_code ec) { 5738a07d286SRatan Gupta if (ec) 5748a07d286SRatan Gupta { 5758a07d286SRatan Gupta BMCWEB_LOG_DEBUG << "Error Occured in Updating the " 5768a07d286SRatan Gupta "groupname attribute"; 5778a07d286SRatan Gupta messages::internalError(asyncResp->res); 5788a07d286SRatan Gupta return; 5798a07d286SRatan Gupta } 5808a07d286SRatan Gupta auto& serverTypeJson = 5818a07d286SRatan Gupta asyncResp->res.jsonValue[ldapServerElementName]; 5828a07d286SRatan Gupta auto& searchSettingsJson = 5838a07d286SRatan Gupta serverTypeJson["LDAPService"]["SearchSettings"]; 5848a07d286SRatan Gupta searchSettingsJson["GroupsAttribute"] = groupsAttribute; 5858a07d286SRatan Gupta BMCWEB_LOG_DEBUG << "Updated the groupname attr"; 5868a07d286SRatan Gupta }, 5878a07d286SRatan Gupta ldapDbusService, ldapConfigObject, propertyInterface, "Set", 5888a07d286SRatan Gupta ldapConfigInterface, "GroupNameAttribute", 5898a07d286SRatan Gupta std::variant<std::string>(groupsAttribute)); 5908a07d286SRatan Gupta } 5918a07d286SRatan Gupta /** 5928a07d286SRatan Gupta * @brief updates the LDAP service enable and updates the 5938a07d286SRatan Gupta json response with the new value. 5948a07d286SRatan Gupta * @param input JSON data. 5958a07d286SRatan Gupta * @param asyncResp pointer to the JSON response 5968a07d286SRatan Gupta * @param ldapServerElementName Type of LDAP 5978a07d286SRatan Gupta server(openLDAP/ActiveDirectory) 5988a07d286SRatan Gupta */ 5998a07d286SRatan Gupta 6008a07d286SRatan Gupta void handleServiceEnablePatch(bool serviceEnabled, 6018a07d286SRatan Gupta const std::shared_ptr<AsyncResp>& asyncResp, 6028a07d286SRatan Gupta const std::string& ldapServerElementName, 6038a07d286SRatan Gupta const std::string& ldapConfigObject) 6048a07d286SRatan Gupta { 6058a07d286SRatan Gupta crow::connections::systemBus->async_method_call( 6068a07d286SRatan Gupta [asyncResp, serviceEnabled, 6078a07d286SRatan Gupta ldapServerElementName](const boost::system::error_code ec) { 6088a07d286SRatan Gupta if (ec) 6098a07d286SRatan Gupta { 6108a07d286SRatan Gupta BMCWEB_LOG_DEBUG 6118a07d286SRatan Gupta << "Error Occured in Updating the service enable"; 6128a07d286SRatan Gupta messages::internalError(asyncResp->res); 6138a07d286SRatan Gupta return; 6148a07d286SRatan Gupta } 6158a07d286SRatan Gupta asyncResp->res 6168a07d286SRatan Gupta .jsonValue[ldapServerElementName]["ServiceEnabled"] = 6178a07d286SRatan Gupta serviceEnabled; 6188a07d286SRatan Gupta BMCWEB_LOG_DEBUG << "Updated Service enable = " 6198a07d286SRatan Gupta << serviceEnabled; 6208a07d286SRatan Gupta }, 6218a07d286SRatan Gupta ldapDbusService, ldapConfigObject, propertyInterface, "Set", 6228a07d286SRatan Gupta ldapEnableInterface, "Enabled", std::variant<bool>(serviceEnabled)); 6238a07d286SRatan Gupta } 6248a07d286SRatan Gupta 6258a07d286SRatan Gupta /** 6268a07d286SRatan Gupta * @brief Get the required values from the given JSON, validates the 6278a07d286SRatan Gupta * value and create the LDAP config object. 6288a07d286SRatan Gupta * @param input JSON data 6298a07d286SRatan Gupta * @param asyncResp pointer to the JSON response 6308a07d286SRatan Gupta * @param serverType Type of LDAP server(openLDAP/ActiveDirectory) 6318a07d286SRatan Gupta */ 6328a07d286SRatan Gupta 6338a07d286SRatan Gupta void handleLDAPPatch(nlohmann::json& input, 6348a07d286SRatan Gupta const std::shared_ptr<AsyncResp>& asyncResp, 6358a07d286SRatan Gupta const crow::Request& req, 6368a07d286SRatan Gupta const std::vector<std::string>& params, 6378a07d286SRatan Gupta const std::string& serverType) 6388a07d286SRatan Gupta { 639*eb2bbe56SRatan Gupta std::string dbusObjectPath; 640*eb2bbe56SRatan Gupta if (serverType == "ActiveDirectory") 641*eb2bbe56SRatan Gupta { 642*eb2bbe56SRatan Gupta dbusObjectPath = ADConfigObject; 643*eb2bbe56SRatan Gupta } 644*eb2bbe56SRatan Gupta else if (serverType == "LDAP") 645*eb2bbe56SRatan Gupta { 646*eb2bbe56SRatan Gupta dbusObjectPath = ldapConfigObject; 647*eb2bbe56SRatan Gupta } 648*eb2bbe56SRatan Gupta 6498a07d286SRatan Gupta std::optional<nlohmann::json> authentication; 6508a07d286SRatan Gupta std::optional<nlohmann::json> ldapService; 6518a07d286SRatan Gupta std::optional<std::string> accountProviderType; 6528a07d286SRatan Gupta std::optional<std::vector<std::string>> serviceAddressList; 6538a07d286SRatan Gupta std::optional<bool> serviceEnabled; 6548a07d286SRatan Gupta std::optional<std::vector<std::string>> baseDNList; 6558a07d286SRatan Gupta std::optional<std::string> userNameAttribute; 6568a07d286SRatan Gupta std::optional<std::string> groupsAttribute; 6578a07d286SRatan Gupta std::optional<std::string> userName; 6588a07d286SRatan Gupta std::optional<std::string> password; 6598a07d286SRatan Gupta 6608a07d286SRatan Gupta if (!json_util::readJson(input, asyncResp->res, "Authentication", 6618a07d286SRatan Gupta authentication, "LDAPService", ldapService, 6628a07d286SRatan Gupta "ServiceAddresses", serviceAddressList, 6638a07d286SRatan Gupta "AccountProviderType", accountProviderType, 6648a07d286SRatan Gupta "ServiceEnabled", serviceEnabled)) 6658a07d286SRatan Gupta { 6668a07d286SRatan Gupta return; 6678a07d286SRatan Gupta } 6688a07d286SRatan Gupta 6698a07d286SRatan Gupta if (authentication) 6708a07d286SRatan Gupta { 6718a07d286SRatan Gupta parseLDAPAuthenticationJson(*authentication, asyncResp, userName, 6728a07d286SRatan Gupta password); 6738a07d286SRatan Gupta } 6748a07d286SRatan Gupta if (ldapService) 6758a07d286SRatan Gupta { 6768a07d286SRatan Gupta parseLDAPServiceJson(*ldapService, asyncResp, baseDNList, 6778a07d286SRatan Gupta userNameAttribute, groupsAttribute); 6788a07d286SRatan Gupta } 6798a07d286SRatan Gupta if (accountProviderType) 6808a07d286SRatan Gupta { 6818a07d286SRatan Gupta messages::propertyNotWritable(asyncResp->res, 6828a07d286SRatan Gupta "AccountProviderType"); 6838a07d286SRatan Gupta } 6848a07d286SRatan Gupta if (serviceAddressList) 6858a07d286SRatan Gupta { 6868a07d286SRatan Gupta if ((*serviceAddressList).size() == 0) 6878a07d286SRatan Gupta { 6888a07d286SRatan Gupta messages::propertyValueNotInList(asyncResp->res, "[]", 6898a07d286SRatan Gupta "ServiceAddress"); 6908a07d286SRatan Gupta return; 6918a07d286SRatan Gupta } 6928a07d286SRatan Gupta } 6938a07d286SRatan Gupta if (baseDNList) 6948a07d286SRatan Gupta { 6958a07d286SRatan Gupta if ((*baseDNList).size() == 0) 6968a07d286SRatan Gupta { 6978a07d286SRatan Gupta messages::propertyValueNotInList(asyncResp->res, "[]", 6988a07d286SRatan Gupta "BaseDistinguishedNames"); 6998a07d286SRatan Gupta return; 7008a07d286SRatan Gupta } 7018a07d286SRatan Gupta } 7028a07d286SRatan Gupta 7038a07d286SRatan Gupta // nothing to update, then return 7048a07d286SRatan Gupta if (!userName && !password && !serviceAddressList && !baseDNList && 7058a07d286SRatan Gupta !userNameAttribute && !groupsAttribute && !serviceEnabled) 7068a07d286SRatan Gupta { 7078a07d286SRatan Gupta return; 7088a07d286SRatan Gupta } 7098a07d286SRatan Gupta 7108a07d286SRatan Gupta // Get the existing resource first then keep modifying 7118a07d286SRatan Gupta // whenever any property gets updated. 712ab828d7cSRatan Gupta getLDAPConfigData(serverType, [this, asyncResp, userName, password, 713ab828d7cSRatan Gupta baseDNList, userNameAttribute, 714ab828d7cSRatan Gupta groupsAttribute, accountProviderType, 715*eb2bbe56SRatan Gupta serviceAddressList, serviceEnabled, 716*eb2bbe56SRatan Gupta dbusObjectPath]( 717ab828d7cSRatan Gupta bool success, LDAPConfigData confData, 718ab828d7cSRatan Gupta const std::string& serverType) { 7198a07d286SRatan Gupta if (!success) 7208a07d286SRatan Gupta { 7218a07d286SRatan Gupta messages::internalError(asyncResp->res); 7228a07d286SRatan Gupta return; 7238a07d286SRatan Gupta } 724ab828d7cSRatan Gupta parseLDAPConfigData(asyncResp->res.jsonValue, confData, serverType); 7258a07d286SRatan Gupta if (confData.serviceEnabled) 7268a07d286SRatan Gupta { 7278a07d286SRatan Gupta // Disable the service first and update the rest of 7288a07d286SRatan Gupta // the properties. 7298a07d286SRatan Gupta handleServiceEnablePatch(false, asyncResp, serverType, 730*eb2bbe56SRatan Gupta dbusObjectPath); 7318a07d286SRatan Gupta } 7328a07d286SRatan Gupta 7338a07d286SRatan Gupta if (serviceAddressList) 7348a07d286SRatan Gupta { 7358a07d286SRatan Gupta handleServiceAddressPatch(*serviceAddressList, asyncResp, 736*eb2bbe56SRatan Gupta serverType, dbusObjectPath); 7378a07d286SRatan Gupta } 7388a07d286SRatan Gupta if (userName) 7398a07d286SRatan Gupta { 7408a07d286SRatan Gupta handleUserNamePatch(*userName, asyncResp, serverType, 741*eb2bbe56SRatan Gupta dbusObjectPath); 7428a07d286SRatan Gupta } 7438a07d286SRatan Gupta if (password) 7448a07d286SRatan Gupta { 7458a07d286SRatan Gupta handlePasswordPatch(*password, asyncResp, serverType, 746*eb2bbe56SRatan Gupta dbusObjectPath); 7478a07d286SRatan Gupta } 7488a07d286SRatan Gupta 7498a07d286SRatan Gupta if (baseDNList) 7508a07d286SRatan Gupta { 7518a07d286SRatan Gupta handleBaseDNPatch(*baseDNList, asyncResp, serverType, 752*eb2bbe56SRatan Gupta dbusObjectPath); 7538a07d286SRatan Gupta } 7548a07d286SRatan Gupta if (userNameAttribute) 7558a07d286SRatan Gupta { 7568a07d286SRatan Gupta handleUserNameAttrPatch(*userNameAttribute, asyncResp, 757*eb2bbe56SRatan Gupta serverType, dbusObjectPath); 7588a07d286SRatan Gupta } 7598a07d286SRatan Gupta if (groupsAttribute) 7608a07d286SRatan Gupta { 7618a07d286SRatan Gupta handleGroupNameAttrPatch(*groupsAttribute, asyncResp, 762*eb2bbe56SRatan Gupta serverType, dbusObjectPath); 7638a07d286SRatan Gupta } 7648a07d286SRatan Gupta if (serviceEnabled) 7658a07d286SRatan Gupta { 7668a07d286SRatan Gupta // if user has given the value as true then enable 7678a07d286SRatan Gupta // the service. if user has given false then no-op 7688a07d286SRatan Gupta // as service is already stopped. 7698a07d286SRatan Gupta if (*serviceEnabled) 7708a07d286SRatan Gupta { 7718a07d286SRatan Gupta handleServiceEnablePatch(*serviceEnabled, asyncResp, 772*eb2bbe56SRatan Gupta serverType, dbusObjectPath); 7738a07d286SRatan Gupta } 7748a07d286SRatan Gupta } 7758a07d286SRatan Gupta else 7768a07d286SRatan Gupta { 7778a07d286SRatan Gupta // if user has not given the service enabled value 7788a07d286SRatan Gupta // then revert it to the same state as it was 7798a07d286SRatan Gupta // before. 7808a07d286SRatan Gupta handleServiceEnablePatch(confData.serviceEnabled, asyncResp, 781*eb2bbe56SRatan Gupta serverType, dbusObjectPath); 7828a07d286SRatan Gupta } 7838a07d286SRatan Gupta }); 7848a07d286SRatan Gupta } 7858a07d286SRatan Gupta 78655c7b7a2SEd Tanous void doGet(crow::Response& res, const crow::Request& req, 7871abe55efSEd Tanous const std::vector<std::string>& params) override 7881abe55efSEd Tanous { 7893d958bbcSAppaRao Puli auto asyncResp = std::make_shared<AsyncResp>(res); 7903d958bbcSAppaRao Puli res.jsonValue = { 7913d958bbcSAppaRao Puli {"@odata.context", "/redfish/v1/" 7923d958bbcSAppaRao Puli "$metadata#AccountService.AccountService"}, 7933d958bbcSAppaRao Puli {"@odata.id", "/redfish/v1/AccountService"}, 7943d958bbcSAppaRao Puli {"@odata.type", "#AccountService." 7956973a582SRatan Gupta "v1_3_1.AccountService"}, 7963d958bbcSAppaRao Puli {"Id", "AccountService"}, 7973d958bbcSAppaRao Puli {"Name", "Account Service"}, 7983d958bbcSAppaRao Puli {"Description", "Account Service"}, 7993d958bbcSAppaRao Puli {"ServiceEnabled", true}, 800343ff2e1SAppaRao Puli {"MaxPasswordLength", 20}, 8013d958bbcSAppaRao Puli {"Accounts", 8023d958bbcSAppaRao Puli {{"@odata.id", "/redfish/v1/AccountService/Accounts"}}}, 8033d958bbcSAppaRao Puli {"Roles", {{"@odata.id", "/redfish/v1/AccountService/Roles"}}}}; 8040f74e643SEd Tanous 8053d958bbcSAppaRao Puli crow::connections::systemBus->async_method_call( 8063d958bbcSAppaRao Puli [asyncResp]( 8073d958bbcSAppaRao Puli const boost::system::error_code ec, 8083d958bbcSAppaRao Puli const std::vector<std::pair< 809abf2add6SEd Tanous std::string, std::variant<uint32_t, uint16_t, uint8_t>>>& 8103d958bbcSAppaRao Puli propertiesList) { 8113d958bbcSAppaRao Puli if (ec) 8123d958bbcSAppaRao Puli { 8133d958bbcSAppaRao Puli messages::internalError(asyncResp->res); 8143d958bbcSAppaRao Puli return; 8153d958bbcSAppaRao Puli } 8163d958bbcSAppaRao Puli BMCWEB_LOG_DEBUG << "Got " << propertiesList.size() 8173d958bbcSAppaRao Puli << "properties for AccountService"; 8183d958bbcSAppaRao Puli for (const std::pair<std::string, 819abf2add6SEd Tanous std::variant<uint32_t, uint16_t, uint8_t>>& 8203d958bbcSAppaRao Puli property : propertiesList) 8213d958bbcSAppaRao Puli { 8223d958bbcSAppaRao Puli if (property.first == "MinPasswordLength") 8233d958bbcSAppaRao Puli { 8243d958bbcSAppaRao Puli const uint8_t* value = 825abf2add6SEd Tanous std::get_if<uint8_t>(&property.second); 8263d958bbcSAppaRao Puli if (value != nullptr) 8273d958bbcSAppaRao Puli { 8283d958bbcSAppaRao Puli asyncResp->res.jsonValue["MinPasswordLength"] = 8293d958bbcSAppaRao Puli *value; 8303d958bbcSAppaRao Puli } 8313d958bbcSAppaRao Puli } 8323d958bbcSAppaRao Puli if (property.first == "AccountUnlockTimeout") 8333d958bbcSAppaRao Puli { 8343d958bbcSAppaRao Puli const uint32_t* value = 835abf2add6SEd Tanous std::get_if<uint32_t>(&property.second); 8363d958bbcSAppaRao Puli if (value != nullptr) 8373d958bbcSAppaRao Puli { 8383d958bbcSAppaRao Puli asyncResp->res.jsonValue["AccountLockoutDuration"] = 8393d958bbcSAppaRao Puli *value; 8403d958bbcSAppaRao Puli } 8413d958bbcSAppaRao Puli } 8423d958bbcSAppaRao Puli if (property.first == "MaxLoginAttemptBeforeLockout") 8433d958bbcSAppaRao Puli { 8443d958bbcSAppaRao Puli const uint16_t* value = 845abf2add6SEd Tanous std::get_if<uint16_t>(&property.second); 8463d958bbcSAppaRao Puli if (value != nullptr) 8473d958bbcSAppaRao Puli { 8483d958bbcSAppaRao Puli asyncResp->res 8493d958bbcSAppaRao Puli .jsonValue["AccountLockoutThreshold"] = *value; 8503d958bbcSAppaRao Puli } 8513d958bbcSAppaRao Puli } 8523d958bbcSAppaRao Puli } 8533d958bbcSAppaRao Puli }, 8543d958bbcSAppaRao Puli "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user", 8553d958bbcSAppaRao Puli "org.freedesktop.DBus.Properties", "GetAll", 8563d958bbcSAppaRao Puli "xyz.openbmc_project.User.AccountPolicy"); 8576973a582SRatan Gupta 858ab828d7cSRatan Gupta auto callback = [asyncResp](bool success, LDAPConfigData& confData, 859ab828d7cSRatan Gupta const std::string& ldapType) { 860ab828d7cSRatan Gupta parseLDAPConfigData(asyncResp->res.jsonValue, confData, ldapType); 861ab828d7cSRatan Gupta }; 862ab828d7cSRatan Gupta 863ab828d7cSRatan Gupta getLDAPConfigData("LDAP", callback); 864ab828d7cSRatan Gupta getLDAPConfigData("ActiveDirectory", callback); 8653d958bbcSAppaRao Puli } 8666973a582SRatan Gupta 8673d958bbcSAppaRao Puli void doPatch(crow::Response& res, const crow::Request& req, 8683d958bbcSAppaRao Puli const std::vector<std::string>& params) override 8693d958bbcSAppaRao Puli { 8703d958bbcSAppaRao Puli auto asyncResp = std::make_shared<AsyncResp>(res); 8713d958bbcSAppaRao Puli 8723d958bbcSAppaRao Puli std::optional<uint32_t> unlockTimeout; 8733d958bbcSAppaRao Puli std::optional<uint16_t> lockoutThreshold; 87419fb6e71SRatan Gupta std::optional<uint16_t> minPasswordLength; 87519fb6e71SRatan Gupta std::optional<uint16_t> maxPasswordLength; 8768a07d286SRatan Gupta std::optional<nlohmann::json> ldapObject; 877*eb2bbe56SRatan Gupta std::optional<nlohmann::json> activeDirectoryObject; 87819fb6e71SRatan Gupta 8793d958bbcSAppaRao Puli if (!json_util::readJson(req, res, "AccountLockoutDuration", 8803d958bbcSAppaRao Puli unlockTimeout, "AccountLockoutThreshold", 88119fb6e71SRatan Gupta lockoutThreshold, "MaxPasswordLength", 88219fb6e71SRatan Gupta maxPasswordLength, "MinPasswordLength", 883*eb2bbe56SRatan Gupta minPasswordLength, "LDAP", ldapObject, 884*eb2bbe56SRatan Gupta "ActiveDirectory", activeDirectoryObject)) 8853d958bbcSAppaRao Puli { 8863d958bbcSAppaRao Puli return; 8873d958bbcSAppaRao Puli } 88819fb6e71SRatan Gupta 88919fb6e71SRatan Gupta if (minPasswordLength) 89019fb6e71SRatan Gupta { 89119fb6e71SRatan Gupta messages::propertyNotWritable(asyncResp->res, "MinPasswordLength"); 89219fb6e71SRatan Gupta } 89319fb6e71SRatan Gupta 89419fb6e71SRatan Gupta if (maxPasswordLength) 89519fb6e71SRatan Gupta { 89619fb6e71SRatan Gupta messages::propertyNotWritable(asyncResp->res, "MaxPasswordLength"); 89719fb6e71SRatan Gupta } 89819fb6e71SRatan Gupta 8998a07d286SRatan Gupta if (ldapObject) 9008a07d286SRatan Gupta { 9018a07d286SRatan Gupta handleLDAPPatch(*ldapObject, asyncResp, req, params, "LDAP"); 9028a07d286SRatan Gupta } 9038a07d286SRatan Gupta 904*eb2bbe56SRatan Gupta if (activeDirectoryObject) 905*eb2bbe56SRatan Gupta { 906*eb2bbe56SRatan Gupta handleLDAPPatch(*activeDirectoryObject, asyncResp, req, params, 907*eb2bbe56SRatan Gupta "ActiveDirectory"); 908*eb2bbe56SRatan Gupta } 909*eb2bbe56SRatan Gupta 9103d958bbcSAppaRao Puli if (unlockTimeout) 9113d958bbcSAppaRao Puli { 9123d958bbcSAppaRao Puli crow::connections::systemBus->async_method_call( 9133d958bbcSAppaRao Puli [asyncResp](const boost::system::error_code ec) { 9143d958bbcSAppaRao Puli if (ec) 9153d958bbcSAppaRao Puli { 9163d958bbcSAppaRao Puli messages::internalError(asyncResp->res); 9173d958bbcSAppaRao Puli return; 9183d958bbcSAppaRao Puli } 919add6133bSRatan Gupta messages::success(asyncResp->res); 9203d958bbcSAppaRao Puli }, 9213d958bbcSAppaRao Puli "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user", 9223d958bbcSAppaRao Puli "org.freedesktop.DBus.Properties", "Set", 9233d958bbcSAppaRao Puli "xyz.openbmc_project.User.AccountPolicy", 924abf2add6SEd Tanous "AccountUnlockTimeout", std::variant<uint32_t>(*unlockTimeout)); 9253d958bbcSAppaRao Puli } 9263d958bbcSAppaRao Puli if (lockoutThreshold) 9273d958bbcSAppaRao Puli { 9283d958bbcSAppaRao Puli crow::connections::systemBus->async_method_call( 9293d958bbcSAppaRao Puli [asyncResp](const boost::system::error_code ec) { 9303d958bbcSAppaRao Puli if (ec) 9313d958bbcSAppaRao Puli { 9323d958bbcSAppaRao Puli messages::internalError(asyncResp->res); 9333d958bbcSAppaRao Puli return; 9343d958bbcSAppaRao Puli } 935add6133bSRatan Gupta messages::success(asyncResp->res); 9363d958bbcSAppaRao Puli }, 9373d958bbcSAppaRao Puli "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user", 9383d958bbcSAppaRao Puli "org.freedesktop.DBus.Properties", "Set", 9393d958bbcSAppaRao Puli "xyz.openbmc_project.User.AccountPolicy", 9403d958bbcSAppaRao Puli "MaxLoginAttemptBeforeLockout", 941abf2add6SEd Tanous std::variant<uint16_t>(*lockoutThreshold)); 9423d958bbcSAppaRao Puli } 94388d16c9aSLewanczyk, Dawid } 94488d16c9aSLewanczyk, Dawid }; 945f00032dbSTanous 946b9b2e0b2SEd Tanous class AccountsCollection : public Node 947b9b2e0b2SEd Tanous { 948b9b2e0b2SEd Tanous public: 949b9b2e0b2SEd Tanous AccountsCollection(CrowApp& app) : 950b9b2e0b2SEd Tanous Node(app, "/redfish/v1/AccountService/Accounts/") 951b9b2e0b2SEd Tanous { 952b9b2e0b2SEd Tanous entityPrivileges = { 953b9b2e0b2SEd Tanous {boost::beast::http::verb::get, 954b9b2e0b2SEd Tanous {{"ConfigureUsers"}, {"ConfigureManager"}}}, 955b9b2e0b2SEd Tanous {boost::beast::http::verb::head, {{"Login"}}}, 956b9b2e0b2SEd Tanous {boost::beast::http::verb::patch, {{"ConfigureUsers"}}}, 957b9b2e0b2SEd Tanous {boost::beast::http::verb::put, {{"ConfigureUsers"}}}, 958b9b2e0b2SEd Tanous {boost::beast::http::verb::delete_, {{"ConfigureUsers"}}}, 959b9b2e0b2SEd Tanous {boost::beast::http::verb::post, {{"ConfigureUsers"}}}}; 960b9b2e0b2SEd Tanous } 961b9b2e0b2SEd Tanous 962b9b2e0b2SEd Tanous private: 963b9b2e0b2SEd Tanous void doGet(crow::Response& res, const crow::Request& req, 964b9b2e0b2SEd Tanous const std::vector<std::string>& params) override 965b9b2e0b2SEd Tanous { 966b9b2e0b2SEd Tanous auto asyncResp = std::make_shared<AsyncResp>(res); 9670f74e643SEd Tanous res.jsonValue = {{"@odata.context", 9680f74e643SEd Tanous "/redfish/v1/" 9690f74e643SEd Tanous "$metadata#ManagerAccountCollection." 9700f74e643SEd Tanous "ManagerAccountCollection"}, 9710f74e643SEd Tanous {"@odata.id", "/redfish/v1/AccountService/Accounts"}, 9720f74e643SEd Tanous {"@odata.type", "#ManagerAccountCollection." 9730f74e643SEd Tanous "ManagerAccountCollection"}, 9740f74e643SEd Tanous {"Name", "Accounts Collection"}, 9750f74e643SEd Tanous {"Description", "BMC User Accounts"}}; 9760f74e643SEd Tanous 977b9b2e0b2SEd Tanous crow::connections::systemBus->async_method_call( 978b9b2e0b2SEd Tanous [asyncResp](const boost::system::error_code ec, 979b9b2e0b2SEd Tanous const ManagedObjectType& users) { 980b9b2e0b2SEd Tanous if (ec) 981b9b2e0b2SEd Tanous { 982f12894f8SJason M. Bills messages::internalError(asyncResp->res); 983b9b2e0b2SEd Tanous return; 984b9b2e0b2SEd Tanous } 985b9b2e0b2SEd Tanous 986b9b2e0b2SEd Tanous nlohmann::json& memberArray = 987b9b2e0b2SEd Tanous asyncResp->res.jsonValue["Members"]; 988b9b2e0b2SEd Tanous memberArray = nlohmann::json::array(); 989b9b2e0b2SEd Tanous 990b9b2e0b2SEd Tanous asyncResp->res.jsonValue["Members@odata.count"] = users.size(); 991b9b2e0b2SEd Tanous for (auto& user : users) 992b9b2e0b2SEd Tanous { 993b9b2e0b2SEd Tanous const std::string& path = 994b9b2e0b2SEd Tanous static_cast<const std::string&>(user.first); 995b9b2e0b2SEd Tanous std::size_t lastIndex = path.rfind("/"); 996b9b2e0b2SEd Tanous if (lastIndex == std::string::npos) 997b9b2e0b2SEd Tanous { 998b9b2e0b2SEd Tanous lastIndex = 0; 999b9b2e0b2SEd Tanous } 1000b9b2e0b2SEd Tanous else 1001b9b2e0b2SEd Tanous { 1002b9b2e0b2SEd Tanous lastIndex += 1; 1003b9b2e0b2SEd Tanous } 1004b9b2e0b2SEd Tanous memberArray.push_back( 1005b9b2e0b2SEd Tanous {{"@odata.id", "/redfish/v1/AccountService/Accounts/" + 1006b9b2e0b2SEd Tanous path.substr(lastIndex)}}); 1007b9b2e0b2SEd Tanous } 1008b9b2e0b2SEd Tanous }, 1009b9b2e0b2SEd Tanous "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user", 1010b9b2e0b2SEd Tanous "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 1011b9b2e0b2SEd Tanous } 101204ae99ecSEd Tanous void doPost(crow::Response& res, const crow::Request& req, 101304ae99ecSEd Tanous const std::vector<std::string>& params) override 101404ae99ecSEd Tanous { 101504ae99ecSEd Tanous auto asyncResp = std::make_shared<AsyncResp>(res); 101604ae99ecSEd Tanous 10179712f8acSEd Tanous std::string username; 10189712f8acSEd Tanous std::string password; 1019a24526dcSEd Tanous std::optional<std::string> roleId("User"); 1020a24526dcSEd Tanous std::optional<bool> enabled = true; 10219712f8acSEd Tanous if (!json_util::readJson(req, res, "UserName", username, "Password", 10229712f8acSEd Tanous password, "RoleId", roleId, "Enabled", 10239712f8acSEd Tanous enabled)) 102404ae99ecSEd Tanous { 102504ae99ecSEd Tanous return; 102604ae99ecSEd Tanous } 102704ae99ecSEd Tanous 102884e12cb7SAppaRao Puli std::string priv = getRoleIdFromPrivilege(*roleId); 102984e12cb7SAppaRao Puli if (priv.empty()) 103004ae99ecSEd Tanous { 1031f12894f8SJason M. Bills messages::propertyValueNotInList(asyncResp->res, *roleId, "RoleId"); 103204ae99ecSEd Tanous return; 103304ae99ecSEd Tanous } 10349712f8acSEd Tanous roleId = priv; 103504ae99ecSEd Tanous 103604ae99ecSEd Tanous crow::connections::systemBus->async_method_call( 10379712f8acSEd Tanous [asyncResp, username, password{std::move(password)}]( 103804ae99ecSEd Tanous const boost::system::error_code ec) { 103904ae99ecSEd Tanous if (ec) 104004ae99ecSEd Tanous { 104104ae99ecSEd Tanous messages::resourceAlreadyExists( 1042f12894f8SJason M. Bills asyncResp->res, "#ManagerAccount.v1_0_3.ManagerAccount", 1043f12894f8SJason M. Bills "UserName", username); 104404ae99ecSEd Tanous return; 104504ae99ecSEd Tanous } 104604ae99ecSEd Tanous 104704ae99ecSEd Tanous if (!pamUpdatePassword(username, password)) 104804ae99ecSEd Tanous { 104904ae99ecSEd Tanous // At this point we have a user that's been created, but the 105004ae99ecSEd Tanous // password set failed. Something is wrong, so delete the 105104ae99ecSEd Tanous // user that we've already created 105204ae99ecSEd Tanous crow::connections::systemBus->async_method_call( 105304ae99ecSEd Tanous [asyncResp](const boost::system::error_code ec) { 105404ae99ecSEd Tanous if (ec) 105504ae99ecSEd Tanous { 1056f12894f8SJason M. Bills messages::internalError(asyncResp->res); 105704ae99ecSEd Tanous return; 105804ae99ecSEd Tanous } 105904ae99ecSEd Tanous 1060f12894f8SJason M. Bills messages::invalidObject(asyncResp->res, "Password"); 106104ae99ecSEd Tanous }, 106204ae99ecSEd Tanous "xyz.openbmc_project.User.Manager", 106304ae99ecSEd Tanous "/xyz/openbmc_project/user/" + username, 106404ae99ecSEd Tanous "xyz.openbmc_project.Object.Delete", "Delete"); 106504ae99ecSEd Tanous 106604ae99ecSEd Tanous BMCWEB_LOG_ERROR << "pamUpdatePassword Failed"; 106704ae99ecSEd Tanous return; 106804ae99ecSEd Tanous } 106904ae99ecSEd Tanous 1070f12894f8SJason M. Bills messages::created(asyncResp->res); 107104ae99ecSEd Tanous asyncResp->res.addHeader( 107204ae99ecSEd Tanous "Location", 107304ae99ecSEd Tanous "/redfish/v1/AccountService/Accounts/" + username); 107404ae99ecSEd Tanous }, 107504ae99ecSEd Tanous "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user", 10769712f8acSEd Tanous "xyz.openbmc_project.User.Manager", "CreateUser", username, 107704ae99ecSEd Tanous std::array<const char*, 4>{"ipmi", "redfish", "ssh", "web"}, 10789712f8acSEd Tanous *roleId, *enabled); 107904ae99ecSEd Tanous } 1080b9b2e0b2SEd Tanous }; 1081b9b2e0b2SEd Tanous 1082b9b2e0b2SEd Tanous class ManagerAccount : public Node 1083b9b2e0b2SEd Tanous { 1084b9b2e0b2SEd Tanous public: 1085b9b2e0b2SEd Tanous ManagerAccount(CrowApp& app) : 1086b9b2e0b2SEd Tanous Node(app, "/redfish/v1/AccountService/Accounts/<str>/", std::string()) 1087b9b2e0b2SEd Tanous { 1088b9b2e0b2SEd Tanous entityPrivileges = { 1089b9b2e0b2SEd Tanous {boost::beast::http::verb::get, 1090b9b2e0b2SEd Tanous {{"ConfigureUsers"}, {"ConfigureManager"}, {"ConfigureSelf"}}}, 1091b9b2e0b2SEd Tanous {boost::beast::http::verb::head, {{"Login"}}}, 1092b9b2e0b2SEd Tanous {boost::beast::http::verb::patch, {{"ConfigureUsers"}}}, 1093b9b2e0b2SEd Tanous {boost::beast::http::verb::put, {{"ConfigureUsers"}}}, 1094b9b2e0b2SEd Tanous {boost::beast::http::verb::delete_, {{"ConfigureUsers"}}}, 1095b9b2e0b2SEd Tanous {boost::beast::http::verb::post, {{"ConfigureUsers"}}}}; 1096b9b2e0b2SEd Tanous } 1097b9b2e0b2SEd Tanous 1098b9b2e0b2SEd Tanous private: 1099b9b2e0b2SEd Tanous void doGet(crow::Response& res, const crow::Request& req, 1100b9b2e0b2SEd Tanous const std::vector<std::string>& params) override 1101b9b2e0b2SEd Tanous { 11020f74e643SEd Tanous res.jsonValue = { 11030f74e643SEd Tanous {"@odata.context", 11040f74e643SEd Tanous "/redfish/v1/$metadata#ManagerAccount.ManagerAccount"}, 11050f74e643SEd Tanous {"@odata.type", "#ManagerAccount.v1_0_3.ManagerAccount"}, 11060f74e643SEd Tanous {"Name", "User Account"}, 11070f74e643SEd Tanous {"Description", "User Account"}, 11080f74e643SEd Tanous {"Password", nullptr}, 110984e12cb7SAppaRao Puli {"RoleId", "Administrator"}}; 11100f74e643SEd Tanous 1111b9b2e0b2SEd Tanous auto asyncResp = std::make_shared<AsyncResp>(res); 1112b9b2e0b2SEd Tanous 1113b9b2e0b2SEd Tanous if (params.size() != 1) 1114b9b2e0b2SEd Tanous { 1115f12894f8SJason M. Bills messages::internalError(asyncResp->res); 1116b9b2e0b2SEd Tanous return; 1117b9b2e0b2SEd Tanous } 1118b9b2e0b2SEd Tanous 1119b9b2e0b2SEd Tanous crow::connections::systemBus->async_method_call( 1120b9b2e0b2SEd Tanous [asyncResp, accountName{std::string(params[0])}]( 1121b9b2e0b2SEd Tanous const boost::system::error_code ec, 1122b9b2e0b2SEd Tanous const ManagedObjectType& users) { 1123b9b2e0b2SEd Tanous if (ec) 1124b9b2e0b2SEd Tanous { 1125f12894f8SJason M. Bills messages::internalError(asyncResp->res); 1126b9b2e0b2SEd Tanous return; 1127b9b2e0b2SEd Tanous } 112884e12cb7SAppaRao Puli auto userIt = users.begin(); 1129b9b2e0b2SEd Tanous 113084e12cb7SAppaRao Puli for (; userIt != users.end(); userIt++) 1131b9b2e0b2SEd Tanous { 113284e12cb7SAppaRao Puli if (boost::ends_with(userIt->first.str, "/" + accountName)) 1133b9b2e0b2SEd Tanous { 113484e12cb7SAppaRao Puli break; 1135b9b2e0b2SEd Tanous } 1136b9b2e0b2SEd Tanous } 113784e12cb7SAppaRao Puli if (userIt == users.end()) 1138b9b2e0b2SEd Tanous { 113984e12cb7SAppaRao Puli messages::resourceNotFound(asyncResp->res, "ManagerAccount", 114084e12cb7SAppaRao Puli accountName); 114184e12cb7SAppaRao Puli return; 114284e12cb7SAppaRao Puli } 114384e12cb7SAppaRao Puli for (const auto& interface : userIt->second) 114465b0dc32SEd Tanous { 114565b0dc32SEd Tanous if (interface.first == 114665b0dc32SEd Tanous "xyz.openbmc_project.User.Attributes") 114765b0dc32SEd Tanous { 114865b0dc32SEd Tanous for (const auto& property : interface.second) 114965b0dc32SEd Tanous { 115065b0dc32SEd Tanous if (property.first == "UserEnabled") 115165b0dc32SEd Tanous { 115265b0dc32SEd Tanous const bool* userEnabled = 1153abf2add6SEd Tanous std::get_if<bool>(&property.second); 115465b0dc32SEd Tanous if (userEnabled == nullptr) 115565b0dc32SEd Tanous { 115665b0dc32SEd Tanous BMCWEB_LOG_ERROR 115765b0dc32SEd Tanous << "UserEnabled wasn't a bool"; 115884e12cb7SAppaRao Puli messages::internalError(asyncResp->res); 115984e12cb7SAppaRao Puli return; 116065b0dc32SEd Tanous } 116165b0dc32SEd Tanous asyncResp->res.jsonValue["Enabled"] = 116265b0dc32SEd Tanous *userEnabled; 116365b0dc32SEd Tanous } 116465b0dc32SEd Tanous else if (property.first == 116565b0dc32SEd Tanous "UserLockedForFailedAttempt") 116665b0dc32SEd Tanous { 116765b0dc32SEd Tanous const bool* userLocked = 1168abf2add6SEd Tanous std::get_if<bool>(&property.second); 116965b0dc32SEd Tanous if (userLocked == nullptr) 117065b0dc32SEd Tanous { 117184e12cb7SAppaRao Puli BMCWEB_LOG_ERROR << "UserLockedForF" 117284e12cb7SAppaRao Puli "ailedAttempt " 117384e12cb7SAppaRao Puli "wasn't a bool"; 117484e12cb7SAppaRao Puli messages::internalError(asyncResp->res); 117584e12cb7SAppaRao Puli return; 117665b0dc32SEd Tanous } 117765b0dc32SEd Tanous asyncResp->res.jsonValue["Locked"] = 117865b0dc32SEd Tanous *userLocked; 117924c8542dSRatan Gupta asyncResp->res.jsonValue 118024c8542dSRatan Gupta ["Locked@Redfish.AllowableValues"] = { 11814d64ce34SGunnar Mills "false"}; 118265b0dc32SEd Tanous } 118384e12cb7SAppaRao Puli else if (property.first == "UserPrivilege") 118484e12cb7SAppaRao Puli { 118584e12cb7SAppaRao Puli const std::string* userRolePtr = 1186abf2add6SEd Tanous std::get_if<std::string>(&property.second); 118784e12cb7SAppaRao Puli if (userRolePtr == nullptr) 118884e12cb7SAppaRao Puli { 118984e12cb7SAppaRao Puli BMCWEB_LOG_ERROR 119084e12cb7SAppaRao Puli << "UserPrivilege wasn't a " 119184e12cb7SAppaRao Puli "string"; 119284e12cb7SAppaRao Puli messages::internalError(asyncResp->res); 119384e12cb7SAppaRao Puli return; 119484e12cb7SAppaRao Puli } 119584e12cb7SAppaRao Puli std::string priv = 119684e12cb7SAppaRao Puli getPrivilegeFromRoleId(*userRolePtr); 119784e12cb7SAppaRao Puli if (priv.empty()) 119884e12cb7SAppaRao Puli { 119984e12cb7SAppaRao Puli BMCWEB_LOG_ERROR << "Invalid user role"; 120084e12cb7SAppaRao Puli messages::internalError(asyncResp->res); 120184e12cb7SAppaRao Puli return; 120284e12cb7SAppaRao Puli } 120384e12cb7SAppaRao Puli asyncResp->res.jsonValue["RoleId"] = priv; 120484e12cb7SAppaRao Puli 120584e12cb7SAppaRao Puli asyncResp->res.jsonValue["Links"]["Role"] = { 120684e12cb7SAppaRao Puli {"@odata.id", "/redfish/v1/AccountService/" 120784e12cb7SAppaRao Puli "Roles/" + 120884e12cb7SAppaRao Puli priv}}; 120984e12cb7SAppaRao Puli } 121065b0dc32SEd Tanous } 121165b0dc32SEd Tanous } 121265b0dc32SEd Tanous } 121365b0dc32SEd Tanous 1214b9b2e0b2SEd Tanous asyncResp->res.jsonValue["@odata.id"] = 121584e12cb7SAppaRao Puli "/redfish/v1/AccountService/Accounts/" + accountName; 1216b9b2e0b2SEd Tanous asyncResp->res.jsonValue["Id"] = accountName; 1217b9b2e0b2SEd Tanous asyncResp->res.jsonValue["UserName"] = accountName; 1218b9b2e0b2SEd Tanous }, 1219b9b2e0b2SEd Tanous "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user", 1220b9b2e0b2SEd Tanous "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 1221b9b2e0b2SEd Tanous } 1222a840879dSEd Tanous 1223a840879dSEd Tanous void doPatch(crow::Response& res, const crow::Request& req, 1224a840879dSEd Tanous const std::vector<std::string>& params) override 1225a840879dSEd Tanous { 1226a840879dSEd Tanous auto asyncResp = std::make_shared<AsyncResp>(res); 1227a840879dSEd Tanous if (params.size() != 1) 1228a840879dSEd Tanous { 1229f12894f8SJason M. Bills messages::internalError(asyncResp->res); 1230a840879dSEd Tanous return; 1231a840879dSEd Tanous } 1232a840879dSEd Tanous 1233a24526dcSEd Tanous std::optional<std::string> newUserName; 1234a24526dcSEd Tanous std::optional<std::string> password; 1235a24526dcSEd Tanous std::optional<bool> enabled; 1236a24526dcSEd Tanous std::optional<std::string> roleId; 123724c8542dSRatan Gupta std::optional<bool> locked; 123884e12cb7SAppaRao Puli if (!json_util::readJson(req, res, "UserName", newUserName, "Password", 123924c8542dSRatan Gupta password, "RoleId", roleId, "Enabled", enabled, 124024c8542dSRatan Gupta "Locked", locked)) 1241a840879dSEd Tanous { 1242a840879dSEd Tanous return; 1243a840879dSEd Tanous } 1244a840879dSEd Tanous 124584e12cb7SAppaRao Puli const std::string& username = params[0]; 124684e12cb7SAppaRao Puli 124784e12cb7SAppaRao Puli if (!newUserName) 1248a840879dSEd Tanous { 124984e12cb7SAppaRao Puli // If the username isn't being updated, we can update the properties 125084e12cb7SAppaRao Puli // directly 125124c8542dSRatan Gupta updateUserProperties(asyncResp, username, password, enabled, roleId, 125224c8542dSRatan Gupta locked); 125384e12cb7SAppaRao Puli return; 125484e12cb7SAppaRao Puli } 125584e12cb7SAppaRao Puli else 125684e12cb7SAppaRao Puli { 125784e12cb7SAppaRao Puli crow::connections::systemBus->async_method_call( 125884e12cb7SAppaRao Puli [this, asyncResp, username, password(std::move(password)), 125984e12cb7SAppaRao Puli roleId(std::move(roleId)), enabled(std::move(enabled)), 126024c8542dSRatan Gupta newUser{std::string(*newUserName)}, locked(std::move(locked))]( 126184e12cb7SAppaRao Puli const boost::system::error_code ec) { 126284e12cb7SAppaRao Puli if (ec) 126384e12cb7SAppaRao Puli { 126484e12cb7SAppaRao Puli BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec; 1265a840879dSEd Tanous messages::resourceNotFound( 126684e12cb7SAppaRao Puli asyncResp->res, 126784e12cb7SAppaRao Puli "#ManagerAccount.v1_0_3.ManagerAccount", username); 1268a840879dSEd Tanous return; 1269a840879dSEd Tanous } 1270a840879dSEd Tanous 127184e12cb7SAppaRao Puli updateUserProperties(asyncResp, newUser, password, enabled, 127224c8542dSRatan Gupta roleId, locked); 127384e12cb7SAppaRao Puli }, 127484e12cb7SAppaRao Puli "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user", 127584e12cb7SAppaRao Puli "xyz.openbmc_project.User.Manager", "RenameUser", username, 127684e12cb7SAppaRao Puli *newUserName); 127784e12cb7SAppaRao Puli } 127884e12cb7SAppaRao Puli } 127984e12cb7SAppaRao Puli 128084e12cb7SAppaRao Puli void updateUserProperties(std::shared_ptr<AsyncResp> asyncResp, 128184e12cb7SAppaRao Puli const std::string& username, 1282a24526dcSEd Tanous std::optional<std::string> password, 1283a24526dcSEd Tanous std::optional<bool> enabled, 128424c8542dSRatan Gupta std::optional<std::string> roleId, 128524c8542dSRatan Gupta std::optional<bool> locked) 128684e12cb7SAppaRao Puli { 12879712f8acSEd Tanous if (password) 1288a840879dSEd Tanous { 12899712f8acSEd Tanous if (!pamUpdatePassword(username, *password)) 1290a840879dSEd Tanous { 1291a840879dSEd Tanous BMCWEB_LOG_ERROR << "pamUpdatePassword Failed"; 1292f12894f8SJason M. Bills messages::internalError(asyncResp->res); 1293a840879dSEd Tanous return; 1294a840879dSEd Tanous } 1295a840879dSEd Tanous } 1296a840879dSEd Tanous 129724c8542dSRatan Gupta std::string dbusObjectPath = "/xyz/openbmc_project/user/" + username; 129824c8542dSRatan Gupta dbus::utility::escapePathForDbus(dbusObjectPath); 129924c8542dSRatan Gupta 130022c33710SRatan Gupta dbus::utility::checkDbusPathExists( 130124c8542dSRatan Gupta dbusObjectPath, 130224c8542dSRatan Gupta [dbusObjectPath(std::move(dbusObjectPath)), username, 130324c8542dSRatan Gupta password(std::move(password)), roleId(std::move(roleId)), 130424c8542dSRatan Gupta enabled(std::move(enabled)), locked(std::move(locked)), 130524c8542dSRatan Gupta asyncResp{std::move(asyncResp)}](int rc) { 130624c8542dSRatan Gupta if (!rc) 130724c8542dSRatan Gupta { 130824c8542dSRatan Gupta messages::invalidObject(asyncResp->res, username.c_str()); 130924c8542dSRatan Gupta return; 131024c8542dSRatan Gupta } 13119712f8acSEd Tanous if (enabled) 1312a840879dSEd Tanous { 1313a840879dSEd Tanous crow::connections::systemBus->async_method_call( 1314a840879dSEd Tanous [asyncResp](const boost::system::error_code ec) { 1315a840879dSEd Tanous if (ec) 1316a840879dSEd Tanous { 131724c8542dSRatan Gupta BMCWEB_LOG_ERROR << "D-Bus responses error: " 131824c8542dSRatan Gupta << ec; 1319f12894f8SJason M. Bills messages::internalError(asyncResp->res); 1320a840879dSEd Tanous return; 1321a840879dSEd Tanous } 132284e12cb7SAppaRao Puli messages::success(asyncResp->res); 132384e12cb7SAppaRao Puli return; 132484e12cb7SAppaRao Puli }, 132584e12cb7SAppaRao Puli "xyz.openbmc_project.User.Manager", 132624c8542dSRatan Gupta dbusObjectPath.c_str(), 132784e12cb7SAppaRao Puli "org.freedesktop.DBus.Properties", "Set", 132884e12cb7SAppaRao Puli "xyz.openbmc_project.User.Attributes", "UserEnabled", 1329abf2add6SEd Tanous std::variant<bool>{*enabled}); 133084e12cb7SAppaRao Puli } 133184e12cb7SAppaRao Puli 133284e12cb7SAppaRao Puli if (roleId) 133384e12cb7SAppaRao Puli { 133484e12cb7SAppaRao Puli std::string priv = getRoleIdFromPrivilege(*roleId); 133584e12cb7SAppaRao Puli if (priv.empty()) 133684e12cb7SAppaRao Puli { 133724c8542dSRatan Gupta messages::propertyValueNotInList(asyncResp->res, 133824c8542dSRatan Gupta *roleId, "RoleId"); 133984e12cb7SAppaRao Puli return; 134084e12cb7SAppaRao Puli } 134184e12cb7SAppaRao Puli 134284e12cb7SAppaRao Puli crow::connections::systemBus->async_method_call( 134384e12cb7SAppaRao Puli [asyncResp](const boost::system::error_code ec) { 134484e12cb7SAppaRao Puli if (ec) 134584e12cb7SAppaRao Puli { 134624c8542dSRatan Gupta BMCWEB_LOG_ERROR << "D-Bus responses error: " 134724c8542dSRatan Gupta << ec; 134884e12cb7SAppaRao Puli messages::internalError(asyncResp->res); 134984e12cb7SAppaRao Puli return; 135084e12cb7SAppaRao Puli } 1351f12894f8SJason M. Bills messages::success(asyncResp->res); 1352a840879dSEd Tanous }, 1353a840879dSEd Tanous "xyz.openbmc_project.User.Manager", 135424c8542dSRatan Gupta dbusObjectPath.c_str(), 1355a840879dSEd Tanous "org.freedesktop.DBus.Properties", "Set", 135684e12cb7SAppaRao Puli "xyz.openbmc_project.User.Attributes", "UserPrivilege", 1357abf2add6SEd Tanous std::variant<std::string>{priv}); 1358a840879dSEd Tanous } 135924c8542dSRatan Gupta 136024c8542dSRatan Gupta if (locked) 136124c8542dSRatan Gupta { 136224c8542dSRatan Gupta // admin can unlock the account which is locked by 136324c8542dSRatan Gupta // successive authentication failures but admin should not 136424c8542dSRatan Gupta // be allowed to lock an account. 136524c8542dSRatan Gupta if (*locked) 136624c8542dSRatan Gupta { 136724c8542dSRatan Gupta messages::propertyValueNotInList(asyncResp->res, "true", 136824c8542dSRatan Gupta "Locked"); 136924c8542dSRatan Gupta return; 137024c8542dSRatan Gupta } 137124c8542dSRatan Gupta 137224c8542dSRatan Gupta crow::connections::systemBus->async_method_call( 137324c8542dSRatan Gupta [asyncResp](const boost::system::error_code ec) { 137424c8542dSRatan Gupta if (ec) 137524c8542dSRatan Gupta { 137624c8542dSRatan Gupta BMCWEB_LOG_ERROR << "D-Bus responses error: " 137724c8542dSRatan Gupta << ec; 137824c8542dSRatan Gupta messages::internalError(asyncResp->res); 137924c8542dSRatan Gupta return; 138024c8542dSRatan Gupta } 138124c8542dSRatan Gupta messages::success(asyncResp->res); 138224c8542dSRatan Gupta return; 138324c8542dSRatan Gupta }, 138424c8542dSRatan Gupta "xyz.openbmc_project.User.Manager", 138524c8542dSRatan Gupta dbusObjectPath.c_str(), 138624c8542dSRatan Gupta "org.freedesktop.DBus.Properties", "Set", 138724c8542dSRatan Gupta "xyz.openbmc_project.User.Attributes", 138824c8542dSRatan Gupta "UserLockedForFailedAttempt", 138924c8542dSRatan Gupta sdbusplus::message::variant<bool>{*locked}); 139024c8542dSRatan Gupta } 139124c8542dSRatan Gupta }); 1392a840879dSEd Tanous } 139306e086d9SEd Tanous 139406e086d9SEd Tanous void doDelete(crow::Response& res, const crow::Request& req, 139506e086d9SEd Tanous const std::vector<std::string>& params) override 139606e086d9SEd Tanous { 139706e086d9SEd Tanous auto asyncResp = std::make_shared<AsyncResp>(res); 139806e086d9SEd Tanous 139906e086d9SEd Tanous if (params.size() != 1) 140006e086d9SEd Tanous { 1401f12894f8SJason M. Bills messages::internalError(asyncResp->res); 140206e086d9SEd Tanous return; 140306e086d9SEd Tanous } 140406e086d9SEd Tanous 140506e086d9SEd Tanous const std::string userPath = "/xyz/openbmc_project/user/" + params[0]; 140606e086d9SEd Tanous 140706e086d9SEd Tanous crow::connections::systemBus->async_method_call( 140806e086d9SEd Tanous [asyncResp, username{std::move(params[0])}]( 140906e086d9SEd Tanous const boost::system::error_code ec) { 141006e086d9SEd Tanous if (ec) 141106e086d9SEd Tanous { 141206e086d9SEd Tanous messages::resourceNotFound( 1413f12894f8SJason M. Bills asyncResp->res, "#ManagerAccount.v1_0_3.ManagerAccount", 1414f12894f8SJason M. Bills username); 141506e086d9SEd Tanous return; 141606e086d9SEd Tanous } 141706e086d9SEd Tanous 1418f12894f8SJason M. Bills messages::accountRemoved(asyncResp->res); 141906e086d9SEd Tanous }, 142006e086d9SEd Tanous "xyz.openbmc_project.User.Manager", userPath, 142106e086d9SEd Tanous "xyz.openbmc_project.Object.Delete", "Delete"); 142206e086d9SEd Tanous } 142384e12cb7SAppaRao Puli }; 142488d16c9aSLewanczyk, Dawid 142588d16c9aSLewanczyk, Dawid } // namespace redfish 1426