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"; 30*ab828d7cSRatan Gupta constexpr const char* ADConfigObject = 31*ab828d7cSRatan Gupta "/xyz/openbmc_project/user/ldap/active_directory"; 32*ab828d7cSRatan 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, 108*ab828d7cSRatan Gupta const LDAPConfigData& confData, 109*ab828d7cSRatan Gupta const std::string& ldapType) 1106973a582SRatan Gupta { 111*ab828d7cSRatan Gupta std::string service = 112*ab828d7cSRatan Gupta (ldapType == "LDAP") ? "LDAPService" : "ActiveDirectoryService"; 113*ab828d7cSRatan 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 { 144*ab828d7cSRatan Gupta callback(false, confData, ldapType); 1456973a582SRatan Gupta BMCWEB_LOG_ERROR << "D-Bus responses error: " << error_code; 1466973a582SRatan Gupta return; 1476973a582SRatan Gupta } 148*ab828d7cSRatan Gupta 149*ab828d7cSRatan Gupta std::string ldapDbusType; 150*ab828d7cSRatan Gupta if (ldapType == "LDAP") 151*ab828d7cSRatan Gupta { 152*ab828d7cSRatan Gupta ldapDbusType = "xyz.openbmc_project.User.Ldap.Config.Type.OpenLdap"; 153*ab828d7cSRatan Gupta } 154*ab828d7cSRatan Gupta else if (ldapType == "ActiveDirectory") 155*ab828d7cSRatan Gupta { 156*ab828d7cSRatan Gupta ldapDbusType = "xyz.openbmc_project.User.Ldap.Config.Type." 157*ab828d7cSRatan Gupta "ActiveDirectory"; 158*ab828d7cSRatan Gupta } 159*ab828d7cSRatan Gupta else 160*ab828d7cSRatan Gupta { 161*ab828d7cSRatan Gupta BMCWEB_LOG_ERROR << "Can't get the DbusType for the given type=" 162*ab828d7cSRatan Gupta << ldapType; 163*ab828d7cSRatan Gupta callback(false, confData, ldapType); 164*ab828d7cSRatan Gupta return; 165*ab828d7cSRatan Gupta } 166*ab828d7cSRatan Gupta 167*ab828d7cSRatan Gupta std::string ldapEnableInterfaceStr = ldapEnableInterface; 168*ab828d7cSRatan Gupta std::string ldapConfigInterfaceStr = ldapConfigInterface; 169*ab828d7cSRatan Gupta 1706973a582SRatan Gupta for (const auto& object : ldapObjects) 1716973a582SRatan Gupta { 172*ab828d7cSRatan Gupta // let's find the object whose ldap type is equal to the given type 173*ab828d7cSRatan Gupta auto intfit = object.second.find(ldapConfigInterfaceStr); 174*ab828d7cSRatan Gupta if (intfit == object.second.end()) 1756973a582SRatan Gupta { 176*ab828d7cSRatan Gupta continue; 177*ab828d7cSRatan Gupta } 178*ab828d7cSRatan Gupta auto propit = intfit->second.find("LDAPType"); 179*ab828d7cSRatan Gupta if (propit == intfit->second.end()) 180*ab828d7cSRatan Gupta { 181*ab828d7cSRatan Gupta continue; 182*ab828d7cSRatan Gupta } 183*ab828d7cSRatan Gupta 184*ab828d7cSRatan Gupta const std::string* value = 185*ab828d7cSRatan Gupta std::get_if<std::string>(&(propit->second)); 186*ab828d7cSRatan Gupta if (value == nullptr || (*value) != ldapDbusType) 187*ab828d7cSRatan Gupta { 188*ab828d7cSRatan Gupta 189*ab828d7cSRatan Gupta // this is not the interested configuration, 190*ab828d7cSRatan Gupta // let's move on to the other configuration. 191*ab828d7cSRatan Gupta continue; 192*ab828d7cSRatan Gupta } 193*ab828d7cSRatan Gupta else 194*ab828d7cSRatan Gupta { 195*ab828d7cSRatan Gupta confData.serverType = *value; 196*ab828d7cSRatan Gupta } 197*ab828d7cSRatan 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 } 256*ab828d7cSRatan Gupta if (confData.serverType == ldapDbusType) 257*ab828d7cSRatan Gupta { 258*ab828d7cSRatan Gupta callback(true, confData, ldapType); 2596973a582SRatan Gupta break; 2606973a582SRatan Gupta } 2616973a582SRatan Gupta } 2626973a582SRatan Gupta }; 263*ab828d7cSRatan 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; 271*ab828d7cSRatan 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 { 6398a07d286SRatan Gupta std::optional<nlohmann::json> authentication; 6408a07d286SRatan Gupta std::optional<nlohmann::json> ldapService; 6418a07d286SRatan Gupta std::optional<std::string> accountProviderType; 6428a07d286SRatan Gupta std::optional<std::vector<std::string>> serviceAddressList; 6438a07d286SRatan Gupta std::optional<bool> serviceEnabled; 6448a07d286SRatan Gupta std::optional<std::vector<std::string>> baseDNList; 6458a07d286SRatan Gupta std::optional<std::string> userNameAttribute; 6468a07d286SRatan Gupta std::optional<std::string> groupsAttribute; 6478a07d286SRatan Gupta std::optional<std::string> userName; 6488a07d286SRatan Gupta std::optional<std::string> password; 6498a07d286SRatan Gupta 6508a07d286SRatan Gupta if (!json_util::readJson(input, asyncResp->res, "Authentication", 6518a07d286SRatan Gupta authentication, "LDAPService", ldapService, 6528a07d286SRatan Gupta "ServiceAddresses", serviceAddressList, 6538a07d286SRatan Gupta "AccountProviderType", accountProviderType, 6548a07d286SRatan Gupta "ServiceEnabled", serviceEnabled)) 6558a07d286SRatan Gupta { 6568a07d286SRatan Gupta return; 6578a07d286SRatan Gupta } 6588a07d286SRatan Gupta 6598a07d286SRatan Gupta if (authentication) 6608a07d286SRatan Gupta { 6618a07d286SRatan Gupta parseLDAPAuthenticationJson(*authentication, asyncResp, userName, 6628a07d286SRatan Gupta password); 6638a07d286SRatan Gupta } 6648a07d286SRatan Gupta if (ldapService) 6658a07d286SRatan Gupta { 6668a07d286SRatan Gupta parseLDAPServiceJson(*ldapService, asyncResp, baseDNList, 6678a07d286SRatan Gupta userNameAttribute, groupsAttribute); 6688a07d286SRatan Gupta } 6698a07d286SRatan Gupta if (accountProviderType) 6708a07d286SRatan Gupta { 6718a07d286SRatan Gupta messages::propertyNotWritable(asyncResp->res, 6728a07d286SRatan Gupta "AccountProviderType"); 6738a07d286SRatan Gupta } 6748a07d286SRatan Gupta if (serviceAddressList) 6758a07d286SRatan Gupta { 6768a07d286SRatan Gupta if ((*serviceAddressList).size() == 0) 6778a07d286SRatan Gupta { 6788a07d286SRatan Gupta messages::propertyValueNotInList(asyncResp->res, "[]", 6798a07d286SRatan Gupta "ServiceAddress"); 6808a07d286SRatan Gupta return; 6818a07d286SRatan Gupta } 6828a07d286SRatan Gupta } 6838a07d286SRatan Gupta if (baseDNList) 6848a07d286SRatan Gupta { 6858a07d286SRatan Gupta if ((*baseDNList).size() == 0) 6868a07d286SRatan Gupta { 6878a07d286SRatan Gupta messages::propertyValueNotInList(asyncResp->res, "[]", 6888a07d286SRatan Gupta "BaseDistinguishedNames"); 6898a07d286SRatan Gupta return; 6908a07d286SRatan Gupta } 6918a07d286SRatan Gupta } 6928a07d286SRatan Gupta 6938a07d286SRatan Gupta // nothing to update, then return 6948a07d286SRatan Gupta if (!userName && !password && !serviceAddressList && !baseDNList && 6958a07d286SRatan Gupta !userNameAttribute && !groupsAttribute && !serviceEnabled) 6968a07d286SRatan Gupta { 6978a07d286SRatan Gupta return; 6988a07d286SRatan Gupta } 6998a07d286SRatan Gupta 7008a07d286SRatan Gupta // Get the existing resource first then keep modifying 7018a07d286SRatan Gupta // whenever any property gets updated. 702*ab828d7cSRatan Gupta getLDAPConfigData(serverType, [this, asyncResp, userName, password, 703*ab828d7cSRatan Gupta baseDNList, userNameAttribute, 704*ab828d7cSRatan Gupta groupsAttribute, accountProviderType, 705*ab828d7cSRatan Gupta serviceAddressList, serviceEnabled]( 706*ab828d7cSRatan Gupta bool success, LDAPConfigData confData, 707*ab828d7cSRatan Gupta const std::string& serverType) { 7088a07d286SRatan Gupta if (!success) 7098a07d286SRatan Gupta { 7108a07d286SRatan Gupta messages::internalError(asyncResp->res); 7118a07d286SRatan Gupta return; 7128a07d286SRatan Gupta } 713*ab828d7cSRatan Gupta parseLDAPConfigData(asyncResp->res.jsonValue, confData, serverType); 7148a07d286SRatan Gupta if (confData.serviceEnabled) 7158a07d286SRatan Gupta { 7168a07d286SRatan Gupta // Disable the service first and update the rest of 7178a07d286SRatan Gupta // the properties. 7188a07d286SRatan Gupta handleServiceEnablePatch(false, asyncResp, serverType, 7198a07d286SRatan Gupta ldapConfigObject); 7208a07d286SRatan Gupta } 7218a07d286SRatan Gupta 7228a07d286SRatan Gupta if (serviceAddressList) 7238a07d286SRatan Gupta { 7248a07d286SRatan Gupta handleServiceAddressPatch(*serviceAddressList, asyncResp, 7258a07d286SRatan Gupta serverType, ldapConfigObject); 7268a07d286SRatan Gupta } 7278a07d286SRatan Gupta if (userName) 7288a07d286SRatan Gupta { 7298a07d286SRatan Gupta handleUserNamePatch(*userName, asyncResp, serverType, 7308a07d286SRatan Gupta ldapConfigObject); 7318a07d286SRatan Gupta } 7328a07d286SRatan Gupta if (password) 7338a07d286SRatan Gupta { 7348a07d286SRatan Gupta handlePasswordPatch(*password, asyncResp, serverType, 7358a07d286SRatan Gupta ldapConfigObject); 7368a07d286SRatan Gupta } 7378a07d286SRatan Gupta 7388a07d286SRatan Gupta if (baseDNList) 7398a07d286SRatan Gupta { 7408a07d286SRatan Gupta handleBaseDNPatch(*baseDNList, asyncResp, serverType, 7418a07d286SRatan Gupta ldapConfigObject); 7428a07d286SRatan Gupta } 7438a07d286SRatan Gupta if (userNameAttribute) 7448a07d286SRatan Gupta { 7458a07d286SRatan Gupta handleUserNameAttrPatch(*userNameAttribute, asyncResp, 7468a07d286SRatan Gupta serverType, ldapConfigObject); 7478a07d286SRatan Gupta } 7488a07d286SRatan Gupta if (groupsAttribute) 7498a07d286SRatan Gupta { 7508a07d286SRatan Gupta handleGroupNameAttrPatch(*groupsAttribute, asyncResp, 7518a07d286SRatan Gupta serverType, ldapConfigObject); 7528a07d286SRatan Gupta } 7538a07d286SRatan Gupta if (serviceEnabled) 7548a07d286SRatan Gupta { 7558a07d286SRatan Gupta // if user has given the value as true then enable 7568a07d286SRatan Gupta // the service. if user has given false then no-op 7578a07d286SRatan Gupta // as service is already stopped. 7588a07d286SRatan Gupta if (*serviceEnabled) 7598a07d286SRatan Gupta { 7608a07d286SRatan Gupta handleServiceEnablePatch(*serviceEnabled, asyncResp, 7618a07d286SRatan Gupta serverType, ldapConfigObject); 7628a07d286SRatan Gupta } 7638a07d286SRatan Gupta } 7648a07d286SRatan Gupta else 7658a07d286SRatan Gupta { 7668a07d286SRatan Gupta // if user has not given the service enabled value 7678a07d286SRatan Gupta // then revert it to the same state as it was 7688a07d286SRatan Gupta // before. 7698a07d286SRatan Gupta handleServiceEnablePatch(confData.serviceEnabled, asyncResp, 7708a07d286SRatan Gupta serverType, ldapConfigObject); 7718a07d286SRatan Gupta } 7728a07d286SRatan Gupta }); 7738a07d286SRatan Gupta } 7748a07d286SRatan Gupta 77555c7b7a2SEd Tanous void doGet(crow::Response& res, const crow::Request& req, 7761abe55efSEd Tanous const std::vector<std::string>& params) override 7771abe55efSEd Tanous { 7783d958bbcSAppaRao Puli auto asyncResp = std::make_shared<AsyncResp>(res); 7793d958bbcSAppaRao Puli res.jsonValue = { 7803d958bbcSAppaRao Puli {"@odata.context", "/redfish/v1/" 7813d958bbcSAppaRao Puli "$metadata#AccountService.AccountService"}, 7823d958bbcSAppaRao Puli {"@odata.id", "/redfish/v1/AccountService"}, 7833d958bbcSAppaRao Puli {"@odata.type", "#AccountService." 7846973a582SRatan Gupta "v1_3_1.AccountService"}, 7853d958bbcSAppaRao Puli {"Id", "AccountService"}, 7863d958bbcSAppaRao Puli {"Name", "Account Service"}, 7873d958bbcSAppaRao Puli {"Description", "Account Service"}, 7883d958bbcSAppaRao Puli {"ServiceEnabled", true}, 789343ff2e1SAppaRao Puli {"MaxPasswordLength", 20}, 7903d958bbcSAppaRao Puli {"Accounts", 7913d958bbcSAppaRao Puli {{"@odata.id", "/redfish/v1/AccountService/Accounts"}}}, 7923d958bbcSAppaRao Puli {"Roles", {{"@odata.id", "/redfish/v1/AccountService/Roles"}}}}; 7930f74e643SEd Tanous 7943d958bbcSAppaRao Puli crow::connections::systemBus->async_method_call( 7953d958bbcSAppaRao Puli [asyncResp]( 7963d958bbcSAppaRao Puli const boost::system::error_code ec, 7973d958bbcSAppaRao Puli const std::vector<std::pair< 798abf2add6SEd Tanous std::string, std::variant<uint32_t, uint16_t, uint8_t>>>& 7993d958bbcSAppaRao Puli propertiesList) { 8003d958bbcSAppaRao Puli if (ec) 8013d958bbcSAppaRao Puli { 8023d958bbcSAppaRao Puli messages::internalError(asyncResp->res); 8033d958bbcSAppaRao Puli return; 8043d958bbcSAppaRao Puli } 8053d958bbcSAppaRao Puli BMCWEB_LOG_DEBUG << "Got " << propertiesList.size() 8063d958bbcSAppaRao Puli << "properties for AccountService"; 8073d958bbcSAppaRao Puli for (const std::pair<std::string, 808abf2add6SEd Tanous std::variant<uint32_t, uint16_t, uint8_t>>& 8093d958bbcSAppaRao Puli property : propertiesList) 8103d958bbcSAppaRao Puli { 8113d958bbcSAppaRao Puli if (property.first == "MinPasswordLength") 8123d958bbcSAppaRao Puli { 8133d958bbcSAppaRao Puli const uint8_t* value = 814abf2add6SEd Tanous std::get_if<uint8_t>(&property.second); 8153d958bbcSAppaRao Puli if (value != nullptr) 8163d958bbcSAppaRao Puli { 8173d958bbcSAppaRao Puli asyncResp->res.jsonValue["MinPasswordLength"] = 8183d958bbcSAppaRao Puli *value; 8193d958bbcSAppaRao Puli } 8203d958bbcSAppaRao Puli } 8213d958bbcSAppaRao Puli if (property.first == "AccountUnlockTimeout") 8223d958bbcSAppaRao Puli { 8233d958bbcSAppaRao Puli const uint32_t* value = 824abf2add6SEd Tanous std::get_if<uint32_t>(&property.second); 8253d958bbcSAppaRao Puli if (value != nullptr) 8263d958bbcSAppaRao Puli { 8273d958bbcSAppaRao Puli asyncResp->res.jsonValue["AccountLockoutDuration"] = 8283d958bbcSAppaRao Puli *value; 8293d958bbcSAppaRao Puli } 8303d958bbcSAppaRao Puli } 8313d958bbcSAppaRao Puli if (property.first == "MaxLoginAttemptBeforeLockout") 8323d958bbcSAppaRao Puli { 8333d958bbcSAppaRao Puli const uint16_t* value = 834abf2add6SEd Tanous std::get_if<uint16_t>(&property.second); 8353d958bbcSAppaRao Puli if (value != nullptr) 8363d958bbcSAppaRao Puli { 8373d958bbcSAppaRao Puli asyncResp->res 8383d958bbcSAppaRao Puli .jsonValue["AccountLockoutThreshold"] = *value; 8393d958bbcSAppaRao Puli } 8403d958bbcSAppaRao Puli } 8413d958bbcSAppaRao Puli } 8423d958bbcSAppaRao Puli }, 8433d958bbcSAppaRao Puli "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user", 8443d958bbcSAppaRao Puli "org.freedesktop.DBus.Properties", "GetAll", 8453d958bbcSAppaRao Puli "xyz.openbmc_project.User.AccountPolicy"); 8466973a582SRatan Gupta 847*ab828d7cSRatan Gupta auto callback = [asyncResp](bool success, LDAPConfigData& confData, 848*ab828d7cSRatan Gupta const std::string& ldapType) { 849*ab828d7cSRatan Gupta parseLDAPConfigData(asyncResp->res.jsonValue, confData, ldapType); 850*ab828d7cSRatan Gupta }; 851*ab828d7cSRatan Gupta 852*ab828d7cSRatan Gupta getLDAPConfigData("LDAP", callback); 853*ab828d7cSRatan Gupta getLDAPConfigData("ActiveDirectory", callback); 8543d958bbcSAppaRao Puli } 8556973a582SRatan Gupta 8563d958bbcSAppaRao Puli void doPatch(crow::Response& res, const crow::Request& req, 8573d958bbcSAppaRao Puli const std::vector<std::string>& params) override 8583d958bbcSAppaRao Puli { 8593d958bbcSAppaRao Puli auto asyncResp = std::make_shared<AsyncResp>(res); 8603d958bbcSAppaRao Puli 8613d958bbcSAppaRao Puli std::optional<uint32_t> unlockTimeout; 8623d958bbcSAppaRao Puli std::optional<uint16_t> lockoutThreshold; 86319fb6e71SRatan Gupta std::optional<uint16_t> minPasswordLength; 86419fb6e71SRatan Gupta std::optional<uint16_t> maxPasswordLength; 8658a07d286SRatan Gupta std::optional<nlohmann::json> ldapObject; 86619fb6e71SRatan Gupta 8673d958bbcSAppaRao Puli if (!json_util::readJson(req, res, "AccountLockoutDuration", 8683d958bbcSAppaRao Puli unlockTimeout, "AccountLockoutThreshold", 86919fb6e71SRatan Gupta lockoutThreshold, "MaxPasswordLength", 87019fb6e71SRatan Gupta maxPasswordLength, "MinPasswordLength", 87119fb6e71SRatan Gupta minPasswordLength)) 8723d958bbcSAppaRao Puli { 8733d958bbcSAppaRao Puli return; 8743d958bbcSAppaRao Puli } 87519fb6e71SRatan Gupta 87619fb6e71SRatan Gupta if (minPasswordLength) 87719fb6e71SRatan Gupta { 87819fb6e71SRatan Gupta messages::propertyNotWritable(asyncResp->res, "MinPasswordLength"); 87919fb6e71SRatan Gupta } 88019fb6e71SRatan Gupta 88119fb6e71SRatan Gupta if (maxPasswordLength) 88219fb6e71SRatan Gupta { 88319fb6e71SRatan Gupta messages::propertyNotWritable(asyncResp->res, "MaxPasswordLength"); 88419fb6e71SRatan Gupta } 88519fb6e71SRatan Gupta 8868a07d286SRatan Gupta if (ldapObject) 8878a07d286SRatan Gupta { 8888a07d286SRatan Gupta handleLDAPPatch(*ldapObject, asyncResp, req, params, "LDAP"); 8898a07d286SRatan Gupta } 8908a07d286SRatan Gupta 8913d958bbcSAppaRao Puli if (unlockTimeout) 8923d958bbcSAppaRao Puli { 8933d958bbcSAppaRao Puli crow::connections::systemBus->async_method_call( 8943d958bbcSAppaRao Puli [asyncResp](const boost::system::error_code ec) { 8953d958bbcSAppaRao Puli if (ec) 8963d958bbcSAppaRao Puli { 8973d958bbcSAppaRao Puli messages::internalError(asyncResp->res); 8983d958bbcSAppaRao Puli return; 8993d958bbcSAppaRao Puli } 900add6133bSRatan Gupta messages::success(asyncResp->res); 9013d958bbcSAppaRao Puli }, 9023d958bbcSAppaRao Puli "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user", 9033d958bbcSAppaRao Puli "org.freedesktop.DBus.Properties", "Set", 9043d958bbcSAppaRao Puli "xyz.openbmc_project.User.AccountPolicy", 905abf2add6SEd Tanous "AccountUnlockTimeout", std::variant<uint32_t>(*unlockTimeout)); 9063d958bbcSAppaRao Puli } 9073d958bbcSAppaRao Puli if (lockoutThreshold) 9083d958bbcSAppaRao Puli { 9093d958bbcSAppaRao Puli crow::connections::systemBus->async_method_call( 9103d958bbcSAppaRao Puli [asyncResp](const boost::system::error_code ec) { 9113d958bbcSAppaRao Puli if (ec) 9123d958bbcSAppaRao Puli { 9133d958bbcSAppaRao Puli messages::internalError(asyncResp->res); 9143d958bbcSAppaRao Puli return; 9153d958bbcSAppaRao Puli } 916add6133bSRatan Gupta messages::success(asyncResp->res); 9173d958bbcSAppaRao Puli }, 9183d958bbcSAppaRao Puli "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user", 9193d958bbcSAppaRao Puli "org.freedesktop.DBus.Properties", "Set", 9203d958bbcSAppaRao Puli "xyz.openbmc_project.User.AccountPolicy", 9213d958bbcSAppaRao Puli "MaxLoginAttemptBeforeLockout", 922abf2add6SEd Tanous std::variant<uint16_t>(*lockoutThreshold)); 9233d958bbcSAppaRao Puli } 92488d16c9aSLewanczyk, Dawid } 92588d16c9aSLewanczyk, Dawid }; 926f00032dbSTanous 927b9b2e0b2SEd Tanous class AccountsCollection : public Node 928b9b2e0b2SEd Tanous { 929b9b2e0b2SEd Tanous public: 930b9b2e0b2SEd Tanous AccountsCollection(CrowApp& app) : 931b9b2e0b2SEd Tanous Node(app, "/redfish/v1/AccountService/Accounts/") 932b9b2e0b2SEd Tanous { 933b9b2e0b2SEd Tanous entityPrivileges = { 934b9b2e0b2SEd Tanous {boost::beast::http::verb::get, 935b9b2e0b2SEd Tanous {{"ConfigureUsers"}, {"ConfigureManager"}}}, 936b9b2e0b2SEd Tanous {boost::beast::http::verb::head, {{"Login"}}}, 937b9b2e0b2SEd Tanous {boost::beast::http::verb::patch, {{"ConfigureUsers"}}}, 938b9b2e0b2SEd Tanous {boost::beast::http::verb::put, {{"ConfigureUsers"}}}, 939b9b2e0b2SEd Tanous {boost::beast::http::verb::delete_, {{"ConfigureUsers"}}}, 940b9b2e0b2SEd Tanous {boost::beast::http::verb::post, {{"ConfigureUsers"}}}}; 941b9b2e0b2SEd Tanous } 942b9b2e0b2SEd Tanous 943b9b2e0b2SEd Tanous private: 944b9b2e0b2SEd Tanous void doGet(crow::Response& res, const crow::Request& req, 945b9b2e0b2SEd Tanous const std::vector<std::string>& params) override 946b9b2e0b2SEd Tanous { 947b9b2e0b2SEd Tanous auto asyncResp = std::make_shared<AsyncResp>(res); 9480f74e643SEd Tanous res.jsonValue = {{"@odata.context", 9490f74e643SEd Tanous "/redfish/v1/" 9500f74e643SEd Tanous "$metadata#ManagerAccountCollection." 9510f74e643SEd Tanous "ManagerAccountCollection"}, 9520f74e643SEd Tanous {"@odata.id", "/redfish/v1/AccountService/Accounts"}, 9530f74e643SEd Tanous {"@odata.type", "#ManagerAccountCollection." 9540f74e643SEd Tanous "ManagerAccountCollection"}, 9550f74e643SEd Tanous {"Name", "Accounts Collection"}, 9560f74e643SEd Tanous {"Description", "BMC User Accounts"}}; 9570f74e643SEd Tanous 958b9b2e0b2SEd Tanous crow::connections::systemBus->async_method_call( 959b9b2e0b2SEd Tanous [asyncResp](const boost::system::error_code ec, 960b9b2e0b2SEd Tanous const ManagedObjectType& users) { 961b9b2e0b2SEd Tanous if (ec) 962b9b2e0b2SEd Tanous { 963f12894f8SJason M. Bills messages::internalError(asyncResp->res); 964b9b2e0b2SEd Tanous return; 965b9b2e0b2SEd Tanous } 966b9b2e0b2SEd Tanous 967b9b2e0b2SEd Tanous nlohmann::json& memberArray = 968b9b2e0b2SEd Tanous asyncResp->res.jsonValue["Members"]; 969b9b2e0b2SEd Tanous memberArray = nlohmann::json::array(); 970b9b2e0b2SEd Tanous 971b9b2e0b2SEd Tanous asyncResp->res.jsonValue["Members@odata.count"] = users.size(); 972b9b2e0b2SEd Tanous for (auto& user : users) 973b9b2e0b2SEd Tanous { 974b9b2e0b2SEd Tanous const std::string& path = 975b9b2e0b2SEd Tanous static_cast<const std::string&>(user.first); 976b9b2e0b2SEd Tanous std::size_t lastIndex = path.rfind("/"); 977b9b2e0b2SEd Tanous if (lastIndex == std::string::npos) 978b9b2e0b2SEd Tanous { 979b9b2e0b2SEd Tanous lastIndex = 0; 980b9b2e0b2SEd Tanous } 981b9b2e0b2SEd Tanous else 982b9b2e0b2SEd Tanous { 983b9b2e0b2SEd Tanous lastIndex += 1; 984b9b2e0b2SEd Tanous } 985b9b2e0b2SEd Tanous memberArray.push_back( 986b9b2e0b2SEd Tanous {{"@odata.id", "/redfish/v1/AccountService/Accounts/" + 987b9b2e0b2SEd Tanous path.substr(lastIndex)}}); 988b9b2e0b2SEd Tanous } 989b9b2e0b2SEd Tanous }, 990b9b2e0b2SEd Tanous "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user", 991b9b2e0b2SEd Tanous "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 992b9b2e0b2SEd Tanous } 99304ae99ecSEd Tanous void doPost(crow::Response& res, const crow::Request& req, 99404ae99ecSEd Tanous const std::vector<std::string>& params) override 99504ae99ecSEd Tanous { 99604ae99ecSEd Tanous auto asyncResp = std::make_shared<AsyncResp>(res); 99704ae99ecSEd Tanous 9989712f8acSEd Tanous std::string username; 9999712f8acSEd Tanous std::string password; 1000a24526dcSEd Tanous std::optional<std::string> roleId("User"); 1001a24526dcSEd Tanous std::optional<bool> enabled = true; 10029712f8acSEd Tanous if (!json_util::readJson(req, res, "UserName", username, "Password", 10039712f8acSEd Tanous password, "RoleId", roleId, "Enabled", 10049712f8acSEd Tanous enabled)) 100504ae99ecSEd Tanous { 100604ae99ecSEd Tanous return; 100704ae99ecSEd Tanous } 100804ae99ecSEd Tanous 100984e12cb7SAppaRao Puli std::string priv = getRoleIdFromPrivilege(*roleId); 101084e12cb7SAppaRao Puli if (priv.empty()) 101104ae99ecSEd Tanous { 1012f12894f8SJason M. Bills messages::propertyValueNotInList(asyncResp->res, *roleId, "RoleId"); 101304ae99ecSEd Tanous return; 101404ae99ecSEd Tanous } 10159712f8acSEd Tanous roleId = priv; 101604ae99ecSEd Tanous 101704ae99ecSEd Tanous crow::connections::systemBus->async_method_call( 10189712f8acSEd Tanous [asyncResp, username, password{std::move(password)}]( 101904ae99ecSEd Tanous const boost::system::error_code ec) { 102004ae99ecSEd Tanous if (ec) 102104ae99ecSEd Tanous { 102204ae99ecSEd Tanous messages::resourceAlreadyExists( 1023f12894f8SJason M. Bills asyncResp->res, "#ManagerAccount.v1_0_3.ManagerAccount", 1024f12894f8SJason M. Bills "UserName", username); 102504ae99ecSEd Tanous return; 102604ae99ecSEd Tanous } 102704ae99ecSEd Tanous 102804ae99ecSEd Tanous if (!pamUpdatePassword(username, password)) 102904ae99ecSEd Tanous { 103004ae99ecSEd Tanous // At this point we have a user that's been created, but the 103104ae99ecSEd Tanous // password set failed. Something is wrong, so delete the 103204ae99ecSEd Tanous // user that we've already created 103304ae99ecSEd Tanous crow::connections::systemBus->async_method_call( 103404ae99ecSEd Tanous [asyncResp](const boost::system::error_code ec) { 103504ae99ecSEd Tanous if (ec) 103604ae99ecSEd Tanous { 1037f12894f8SJason M. Bills messages::internalError(asyncResp->res); 103804ae99ecSEd Tanous return; 103904ae99ecSEd Tanous } 104004ae99ecSEd Tanous 1041f12894f8SJason M. Bills messages::invalidObject(asyncResp->res, "Password"); 104204ae99ecSEd Tanous }, 104304ae99ecSEd Tanous "xyz.openbmc_project.User.Manager", 104404ae99ecSEd Tanous "/xyz/openbmc_project/user/" + username, 104504ae99ecSEd Tanous "xyz.openbmc_project.Object.Delete", "Delete"); 104604ae99ecSEd Tanous 104704ae99ecSEd Tanous BMCWEB_LOG_ERROR << "pamUpdatePassword Failed"; 104804ae99ecSEd Tanous return; 104904ae99ecSEd Tanous } 105004ae99ecSEd Tanous 1051f12894f8SJason M. Bills messages::created(asyncResp->res); 105204ae99ecSEd Tanous asyncResp->res.addHeader( 105304ae99ecSEd Tanous "Location", 105404ae99ecSEd Tanous "/redfish/v1/AccountService/Accounts/" + username); 105504ae99ecSEd Tanous }, 105604ae99ecSEd Tanous "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user", 10579712f8acSEd Tanous "xyz.openbmc_project.User.Manager", "CreateUser", username, 105804ae99ecSEd Tanous std::array<const char*, 4>{"ipmi", "redfish", "ssh", "web"}, 10599712f8acSEd Tanous *roleId, *enabled); 106004ae99ecSEd Tanous } 1061b9b2e0b2SEd Tanous }; 1062b9b2e0b2SEd Tanous 1063b9b2e0b2SEd Tanous class ManagerAccount : public Node 1064b9b2e0b2SEd Tanous { 1065b9b2e0b2SEd Tanous public: 1066b9b2e0b2SEd Tanous ManagerAccount(CrowApp& app) : 1067b9b2e0b2SEd Tanous Node(app, "/redfish/v1/AccountService/Accounts/<str>/", std::string()) 1068b9b2e0b2SEd Tanous { 1069b9b2e0b2SEd Tanous entityPrivileges = { 1070b9b2e0b2SEd Tanous {boost::beast::http::verb::get, 1071b9b2e0b2SEd Tanous {{"ConfigureUsers"}, {"ConfigureManager"}, {"ConfigureSelf"}}}, 1072b9b2e0b2SEd Tanous {boost::beast::http::verb::head, {{"Login"}}}, 1073b9b2e0b2SEd Tanous {boost::beast::http::verb::patch, {{"ConfigureUsers"}}}, 1074b9b2e0b2SEd Tanous {boost::beast::http::verb::put, {{"ConfigureUsers"}}}, 1075b9b2e0b2SEd Tanous {boost::beast::http::verb::delete_, {{"ConfigureUsers"}}}, 1076b9b2e0b2SEd Tanous {boost::beast::http::verb::post, {{"ConfigureUsers"}}}}; 1077b9b2e0b2SEd Tanous } 1078b9b2e0b2SEd Tanous 1079b9b2e0b2SEd Tanous private: 1080b9b2e0b2SEd Tanous void doGet(crow::Response& res, const crow::Request& req, 1081b9b2e0b2SEd Tanous const std::vector<std::string>& params) override 1082b9b2e0b2SEd Tanous { 10830f74e643SEd Tanous res.jsonValue = { 10840f74e643SEd Tanous {"@odata.context", 10850f74e643SEd Tanous "/redfish/v1/$metadata#ManagerAccount.ManagerAccount"}, 10860f74e643SEd Tanous {"@odata.type", "#ManagerAccount.v1_0_3.ManagerAccount"}, 10870f74e643SEd Tanous {"Name", "User Account"}, 10880f74e643SEd Tanous {"Description", "User Account"}, 10890f74e643SEd Tanous {"Password", nullptr}, 109084e12cb7SAppaRao Puli {"RoleId", "Administrator"}}; 10910f74e643SEd Tanous 1092b9b2e0b2SEd Tanous auto asyncResp = std::make_shared<AsyncResp>(res); 1093b9b2e0b2SEd Tanous 1094b9b2e0b2SEd Tanous if (params.size() != 1) 1095b9b2e0b2SEd Tanous { 1096f12894f8SJason M. Bills messages::internalError(asyncResp->res); 1097b9b2e0b2SEd Tanous return; 1098b9b2e0b2SEd Tanous } 1099b9b2e0b2SEd Tanous 1100b9b2e0b2SEd Tanous crow::connections::systemBus->async_method_call( 1101b9b2e0b2SEd Tanous [asyncResp, accountName{std::string(params[0])}]( 1102b9b2e0b2SEd Tanous const boost::system::error_code ec, 1103b9b2e0b2SEd Tanous const ManagedObjectType& users) { 1104b9b2e0b2SEd Tanous if (ec) 1105b9b2e0b2SEd Tanous { 1106f12894f8SJason M. Bills messages::internalError(asyncResp->res); 1107b9b2e0b2SEd Tanous return; 1108b9b2e0b2SEd Tanous } 110984e12cb7SAppaRao Puli auto userIt = users.begin(); 1110b9b2e0b2SEd Tanous 111184e12cb7SAppaRao Puli for (; userIt != users.end(); userIt++) 1112b9b2e0b2SEd Tanous { 111384e12cb7SAppaRao Puli if (boost::ends_with(userIt->first.str, "/" + accountName)) 1114b9b2e0b2SEd Tanous { 111584e12cb7SAppaRao Puli break; 1116b9b2e0b2SEd Tanous } 1117b9b2e0b2SEd Tanous } 111884e12cb7SAppaRao Puli if (userIt == users.end()) 1119b9b2e0b2SEd Tanous { 112084e12cb7SAppaRao Puli messages::resourceNotFound(asyncResp->res, "ManagerAccount", 112184e12cb7SAppaRao Puli accountName); 112284e12cb7SAppaRao Puli return; 112384e12cb7SAppaRao Puli } 112484e12cb7SAppaRao Puli for (const auto& interface : userIt->second) 112565b0dc32SEd Tanous { 112665b0dc32SEd Tanous if (interface.first == 112765b0dc32SEd Tanous "xyz.openbmc_project.User.Attributes") 112865b0dc32SEd Tanous { 112965b0dc32SEd Tanous for (const auto& property : interface.second) 113065b0dc32SEd Tanous { 113165b0dc32SEd Tanous if (property.first == "UserEnabled") 113265b0dc32SEd Tanous { 113365b0dc32SEd Tanous const bool* userEnabled = 1134abf2add6SEd Tanous std::get_if<bool>(&property.second); 113565b0dc32SEd Tanous if (userEnabled == nullptr) 113665b0dc32SEd Tanous { 113765b0dc32SEd Tanous BMCWEB_LOG_ERROR 113865b0dc32SEd Tanous << "UserEnabled wasn't a bool"; 113984e12cb7SAppaRao Puli messages::internalError(asyncResp->res); 114084e12cb7SAppaRao Puli return; 114165b0dc32SEd Tanous } 114265b0dc32SEd Tanous asyncResp->res.jsonValue["Enabled"] = 114365b0dc32SEd Tanous *userEnabled; 114465b0dc32SEd Tanous } 114565b0dc32SEd Tanous else if (property.first == 114665b0dc32SEd Tanous "UserLockedForFailedAttempt") 114765b0dc32SEd Tanous { 114865b0dc32SEd Tanous const bool* userLocked = 1149abf2add6SEd Tanous std::get_if<bool>(&property.second); 115065b0dc32SEd Tanous if (userLocked == nullptr) 115165b0dc32SEd Tanous { 115284e12cb7SAppaRao Puli BMCWEB_LOG_ERROR << "UserLockedForF" 115384e12cb7SAppaRao Puli "ailedAttempt " 115484e12cb7SAppaRao Puli "wasn't a bool"; 115584e12cb7SAppaRao Puli messages::internalError(asyncResp->res); 115684e12cb7SAppaRao Puli return; 115765b0dc32SEd Tanous } 115865b0dc32SEd Tanous asyncResp->res.jsonValue["Locked"] = 115965b0dc32SEd Tanous *userLocked; 116024c8542dSRatan Gupta asyncResp->res.jsonValue 116124c8542dSRatan Gupta ["Locked@Redfish.AllowableValues"] = { 11624d64ce34SGunnar Mills "false"}; 116365b0dc32SEd Tanous } 116484e12cb7SAppaRao Puli else if (property.first == "UserPrivilege") 116584e12cb7SAppaRao Puli { 116684e12cb7SAppaRao Puli const std::string* userRolePtr = 1167abf2add6SEd Tanous std::get_if<std::string>(&property.second); 116884e12cb7SAppaRao Puli if (userRolePtr == nullptr) 116984e12cb7SAppaRao Puli { 117084e12cb7SAppaRao Puli BMCWEB_LOG_ERROR 117184e12cb7SAppaRao Puli << "UserPrivilege wasn't a " 117284e12cb7SAppaRao Puli "string"; 117384e12cb7SAppaRao Puli messages::internalError(asyncResp->res); 117484e12cb7SAppaRao Puli return; 117584e12cb7SAppaRao Puli } 117684e12cb7SAppaRao Puli std::string priv = 117784e12cb7SAppaRao Puli getPrivilegeFromRoleId(*userRolePtr); 117884e12cb7SAppaRao Puli if (priv.empty()) 117984e12cb7SAppaRao Puli { 118084e12cb7SAppaRao Puli BMCWEB_LOG_ERROR << "Invalid user role"; 118184e12cb7SAppaRao Puli messages::internalError(asyncResp->res); 118284e12cb7SAppaRao Puli return; 118384e12cb7SAppaRao Puli } 118484e12cb7SAppaRao Puli asyncResp->res.jsonValue["RoleId"] = priv; 118584e12cb7SAppaRao Puli 118684e12cb7SAppaRao Puli asyncResp->res.jsonValue["Links"]["Role"] = { 118784e12cb7SAppaRao Puli {"@odata.id", "/redfish/v1/AccountService/" 118884e12cb7SAppaRao Puli "Roles/" + 118984e12cb7SAppaRao Puli priv}}; 119084e12cb7SAppaRao Puli } 119165b0dc32SEd Tanous } 119265b0dc32SEd Tanous } 119365b0dc32SEd Tanous } 119465b0dc32SEd Tanous 1195b9b2e0b2SEd Tanous asyncResp->res.jsonValue["@odata.id"] = 119684e12cb7SAppaRao Puli "/redfish/v1/AccountService/Accounts/" + accountName; 1197b9b2e0b2SEd Tanous asyncResp->res.jsonValue["Id"] = accountName; 1198b9b2e0b2SEd Tanous asyncResp->res.jsonValue["UserName"] = accountName; 1199b9b2e0b2SEd Tanous }, 1200b9b2e0b2SEd Tanous "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user", 1201b9b2e0b2SEd Tanous "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 1202b9b2e0b2SEd Tanous } 1203a840879dSEd Tanous 1204a840879dSEd Tanous void doPatch(crow::Response& res, const crow::Request& req, 1205a840879dSEd Tanous const std::vector<std::string>& params) override 1206a840879dSEd Tanous { 1207a840879dSEd Tanous auto asyncResp = std::make_shared<AsyncResp>(res); 1208a840879dSEd Tanous if (params.size() != 1) 1209a840879dSEd Tanous { 1210f12894f8SJason M. Bills messages::internalError(asyncResp->res); 1211a840879dSEd Tanous return; 1212a840879dSEd Tanous } 1213a840879dSEd Tanous 1214a24526dcSEd Tanous std::optional<std::string> newUserName; 1215a24526dcSEd Tanous std::optional<std::string> password; 1216a24526dcSEd Tanous std::optional<bool> enabled; 1217a24526dcSEd Tanous std::optional<std::string> roleId; 121824c8542dSRatan Gupta std::optional<bool> locked; 121984e12cb7SAppaRao Puli if (!json_util::readJson(req, res, "UserName", newUserName, "Password", 122024c8542dSRatan Gupta password, "RoleId", roleId, "Enabled", enabled, 122124c8542dSRatan Gupta "Locked", locked)) 1222a840879dSEd Tanous { 1223a840879dSEd Tanous return; 1224a840879dSEd Tanous } 1225a840879dSEd Tanous 122684e12cb7SAppaRao Puli const std::string& username = params[0]; 122784e12cb7SAppaRao Puli 122884e12cb7SAppaRao Puli if (!newUserName) 1229a840879dSEd Tanous { 123084e12cb7SAppaRao Puli // If the username isn't being updated, we can update the properties 123184e12cb7SAppaRao Puli // directly 123224c8542dSRatan Gupta updateUserProperties(asyncResp, username, password, enabled, roleId, 123324c8542dSRatan Gupta locked); 123484e12cb7SAppaRao Puli return; 123584e12cb7SAppaRao Puli } 123684e12cb7SAppaRao Puli else 123784e12cb7SAppaRao Puli { 123884e12cb7SAppaRao Puli crow::connections::systemBus->async_method_call( 123984e12cb7SAppaRao Puli [this, asyncResp, username, password(std::move(password)), 124084e12cb7SAppaRao Puli roleId(std::move(roleId)), enabled(std::move(enabled)), 124124c8542dSRatan Gupta newUser{std::string(*newUserName)}, locked(std::move(locked))]( 124284e12cb7SAppaRao Puli const boost::system::error_code ec) { 124384e12cb7SAppaRao Puli if (ec) 124484e12cb7SAppaRao Puli { 124584e12cb7SAppaRao Puli BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec; 1246a840879dSEd Tanous messages::resourceNotFound( 124784e12cb7SAppaRao Puli asyncResp->res, 124884e12cb7SAppaRao Puli "#ManagerAccount.v1_0_3.ManagerAccount", username); 1249a840879dSEd Tanous return; 1250a840879dSEd Tanous } 1251a840879dSEd Tanous 125284e12cb7SAppaRao Puli updateUserProperties(asyncResp, newUser, password, enabled, 125324c8542dSRatan Gupta roleId, locked); 125484e12cb7SAppaRao Puli }, 125584e12cb7SAppaRao Puli "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user", 125684e12cb7SAppaRao Puli "xyz.openbmc_project.User.Manager", "RenameUser", username, 125784e12cb7SAppaRao Puli *newUserName); 125884e12cb7SAppaRao Puli } 125984e12cb7SAppaRao Puli } 126084e12cb7SAppaRao Puli 126184e12cb7SAppaRao Puli void updateUserProperties(std::shared_ptr<AsyncResp> asyncResp, 126284e12cb7SAppaRao Puli const std::string& username, 1263a24526dcSEd Tanous std::optional<std::string> password, 1264a24526dcSEd Tanous std::optional<bool> enabled, 126524c8542dSRatan Gupta std::optional<std::string> roleId, 126624c8542dSRatan Gupta std::optional<bool> locked) 126784e12cb7SAppaRao Puli { 12689712f8acSEd Tanous if (password) 1269a840879dSEd Tanous { 12709712f8acSEd Tanous if (!pamUpdatePassword(username, *password)) 1271a840879dSEd Tanous { 1272a840879dSEd Tanous BMCWEB_LOG_ERROR << "pamUpdatePassword Failed"; 1273f12894f8SJason M. Bills messages::internalError(asyncResp->res); 1274a840879dSEd Tanous return; 1275a840879dSEd Tanous } 1276a840879dSEd Tanous } 1277a840879dSEd Tanous 127824c8542dSRatan Gupta std::string dbusObjectPath = "/xyz/openbmc_project/user/" + username; 127924c8542dSRatan Gupta dbus::utility::escapePathForDbus(dbusObjectPath); 128024c8542dSRatan Gupta 128122c33710SRatan Gupta dbus::utility::checkDbusPathExists( 128224c8542dSRatan Gupta dbusObjectPath, 128324c8542dSRatan Gupta [dbusObjectPath(std::move(dbusObjectPath)), username, 128424c8542dSRatan Gupta password(std::move(password)), roleId(std::move(roleId)), 128524c8542dSRatan Gupta enabled(std::move(enabled)), locked(std::move(locked)), 128624c8542dSRatan Gupta asyncResp{std::move(asyncResp)}](int rc) { 128724c8542dSRatan Gupta if (!rc) 128824c8542dSRatan Gupta { 128924c8542dSRatan Gupta messages::invalidObject(asyncResp->res, username.c_str()); 129024c8542dSRatan Gupta return; 129124c8542dSRatan Gupta } 12929712f8acSEd Tanous if (enabled) 1293a840879dSEd Tanous { 1294a840879dSEd Tanous crow::connections::systemBus->async_method_call( 1295a840879dSEd Tanous [asyncResp](const boost::system::error_code ec) { 1296a840879dSEd Tanous if (ec) 1297a840879dSEd Tanous { 129824c8542dSRatan Gupta BMCWEB_LOG_ERROR << "D-Bus responses error: " 129924c8542dSRatan Gupta << ec; 1300f12894f8SJason M. Bills messages::internalError(asyncResp->res); 1301a840879dSEd Tanous return; 1302a840879dSEd Tanous } 130384e12cb7SAppaRao Puli messages::success(asyncResp->res); 130484e12cb7SAppaRao Puli return; 130584e12cb7SAppaRao Puli }, 130684e12cb7SAppaRao Puli "xyz.openbmc_project.User.Manager", 130724c8542dSRatan Gupta dbusObjectPath.c_str(), 130884e12cb7SAppaRao Puli "org.freedesktop.DBus.Properties", "Set", 130984e12cb7SAppaRao Puli "xyz.openbmc_project.User.Attributes", "UserEnabled", 1310abf2add6SEd Tanous std::variant<bool>{*enabled}); 131184e12cb7SAppaRao Puli } 131284e12cb7SAppaRao Puli 131384e12cb7SAppaRao Puli if (roleId) 131484e12cb7SAppaRao Puli { 131584e12cb7SAppaRao Puli std::string priv = getRoleIdFromPrivilege(*roleId); 131684e12cb7SAppaRao Puli if (priv.empty()) 131784e12cb7SAppaRao Puli { 131824c8542dSRatan Gupta messages::propertyValueNotInList(asyncResp->res, 131924c8542dSRatan Gupta *roleId, "RoleId"); 132084e12cb7SAppaRao Puli return; 132184e12cb7SAppaRao Puli } 132284e12cb7SAppaRao Puli 132384e12cb7SAppaRao Puli crow::connections::systemBus->async_method_call( 132484e12cb7SAppaRao Puli [asyncResp](const boost::system::error_code ec) { 132584e12cb7SAppaRao Puli if (ec) 132684e12cb7SAppaRao Puli { 132724c8542dSRatan Gupta BMCWEB_LOG_ERROR << "D-Bus responses error: " 132824c8542dSRatan Gupta << ec; 132984e12cb7SAppaRao Puli messages::internalError(asyncResp->res); 133084e12cb7SAppaRao Puli return; 133184e12cb7SAppaRao Puli } 1332f12894f8SJason M. Bills messages::success(asyncResp->res); 1333a840879dSEd Tanous }, 1334a840879dSEd Tanous "xyz.openbmc_project.User.Manager", 133524c8542dSRatan Gupta dbusObjectPath.c_str(), 1336a840879dSEd Tanous "org.freedesktop.DBus.Properties", "Set", 133784e12cb7SAppaRao Puli "xyz.openbmc_project.User.Attributes", "UserPrivilege", 1338abf2add6SEd Tanous std::variant<std::string>{priv}); 1339a840879dSEd Tanous } 134024c8542dSRatan Gupta 134124c8542dSRatan Gupta if (locked) 134224c8542dSRatan Gupta { 134324c8542dSRatan Gupta // admin can unlock the account which is locked by 134424c8542dSRatan Gupta // successive authentication failures but admin should not 134524c8542dSRatan Gupta // be allowed to lock an account. 134624c8542dSRatan Gupta if (*locked) 134724c8542dSRatan Gupta { 134824c8542dSRatan Gupta messages::propertyValueNotInList(asyncResp->res, "true", 134924c8542dSRatan Gupta "Locked"); 135024c8542dSRatan Gupta return; 135124c8542dSRatan Gupta } 135224c8542dSRatan Gupta 135324c8542dSRatan Gupta crow::connections::systemBus->async_method_call( 135424c8542dSRatan Gupta [asyncResp](const boost::system::error_code ec) { 135524c8542dSRatan Gupta if (ec) 135624c8542dSRatan Gupta { 135724c8542dSRatan Gupta BMCWEB_LOG_ERROR << "D-Bus responses error: " 135824c8542dSRatan Gupta << ec; 135924c8542dSRatan Gupta messages::internalError(asyncResp->res); 136024c8542dSRatan Gupta return; 136124c8542dSRatan Gupta } 136224c8542dSRatan Gupta messages::success(asyncResp->res); 136324c8542dSRatan Gupta return; 136424c8542dSRatan Gupta }, 136524c8542dSRatan Gupta "xyz.openbmc_project.User.Manager", 136624c8542dSRatan Gupta dbusObjectPath.c_str(), 136724c8542dSRatan Gupta "org.freedesktop.DBus.Properties", "Set", 136824c8542dSRatan Gupta "xyz.openbmc_project.User.Attributes", 136924c8542dSRatan Gupta "UserLockedForFailedAttempt", 137024c8542dSRatan Gupta sdbusplus::message::variant<bool>{*locked}); 137124c8542dSRatan Gupta } 137224c8542dSRatan Gupta }); 1373a840879dSEd Tanous } 137406e086d9SEd Tanous 137506e086d9SEd Tanous void doDelete(crow::Response& res, const crow::Request& req, 137606e086d9SEd Tanous const std::vector<std::string>& params) override 137706e086d9SEd Tanous { 137806e086d9SEd Tanous auto asyncResp = std::make_shared<AsyncResp>(res); 137906e086d9SEd Tanous 138006e086d9SEd Tanous if (params.size() != 1) 138106e086d9SEd Tanous { 1382f12894f8SJason M. Bills messages::internalError(asyncResp->res); 138306e086d9SEd Tanous return; 138406e086d9SEd Tanous } 138506e086d9SEd Tanous 138606e086d9SEd Tanous const std::string userPath = "/xyz/openbmc_project/user/" + params[0]; 138706e086d9SEd Tanous 138806e086d9SEd Tanous crow::connections::systemBus->async_method_call( 138906e086d9SEd Tanous [asyncResp, username{std::move(params[0])}]( 139006e086d9SEd Tanous const boost::system::error_code ec) { 139106e086d9SEd Tanous if (ec) 139206e086d9SEd Tanous { 139306e086d9SEd Tanous messages::resourceNotFound( 1394f12894f8SJason M. Bills asyncResp->res, "#ManagerAccount.v1_0_3.ManagerAccount", 1395f12894f8SJason M. Bills username); 139606e086d9SEd Tanous return; 139706e086d9SEd Tanous } 139806e086d9SEd Tanous 1399f12894f8SJason M. Bills messages::accountRemoved(asyncResp->res); 140006e086d9SEd Tanous }, 140106e086d9SEd Tanous "xyz.openbmc_project.User.Manager", userPath, 140206e086d9SEd Tanous "xyz.openbmc_project.Object.Delete", "Delete"); 140306e086d9SEd Tanous } 140484e12cb7SAppaRao Puli }; 140588d16c9aSLewanczyk, Dawid 140688d16c9aSLewanczyk, Dawid } // namespace redfish 1407