188d16c9aSLewanczyk, Dawid /* 288d16c9aSLewanczyk, Dawid // Copyright (c) 2018 Intel Corporation 388d16c9aSLewanczyk, Dawid // 488d16c9aSLewanczyk, Dawid // Licensed under the Apache License, Version 2.0 (the "License"); 588d16c9aSLewanczyk, Dawid // you may not use this file except in compliance with the License. 688d16c9aSLewanczyk, Dawid // You may obtain a copy of the License at 788d16c9aSLewanczyk, Dawid // 888d16c9aSLewanczyk, Dawid // http://www.apache.org/licenses/LICENSE-2.0 988d16c9aSLewanczyk, Dawid // 1088d16c9aSLewanczyk, Dawid // Unless required by applicable law or agreed to in writing, software 1188d16c9aSLewanczyk, Dawid // distributed under the License is distributed on an "AS IS" BASIS, 1288d16c9aSLewanczyk, Dawid // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1388d16c9aSLewanczyk, Dawid // See the License for the specific language governing permissions and 1488d16c9aSLewanczyk, Dawid // limitations under the License. 1588d16c9aSLewanczyk, Dawid */ 1688d16c9aSLewanczyk, Dawid #pragma once 1788d16c9aSLewanczyk, Dawid #include "node.hpp" 1888d16c9aSLewanczyk, Dawid 1924c8542dSRatan Gupta #include <dbus_utility.hpp> 2065b0dc32SEd Tanous #include <error_messages.hpp> 21b9b2e0b2SEd Tanous #include <openbmc_dbus_rest.hpp> 22a840879dSEd Tanous #include <utils/json_utils.hpp> 23abf2add6SEd Tanous #include <variant> 24b9b2e0b2SEd Tanous 251abe55efSEd Tanous namespace redfish 261abe55efSEd Tanous { 2788d16c9aSLewanczyk, Dawid 286973a582SRatan Gupta constexpr const char* ldapConfigObject = 296973a582SRatan Gupta "/xyz/openbmc_project/user/ldap/openldap"; 306973a582SRatan Gupta constexpr const char* ldapRootObject = "/xyz/openbmc_project/user/ldap"; 316973a582SRatan Gupta constexpr const char* ldapDbusService = "xyz.openbmc_project.Ldap.Config"; 326973a582SRatan Gupta constexpr const char* ldapConfigInterface = 336973a582SRatan Gupta "xyz.openbmc_project.User.Ldap.Config"; 346973a582SRatan Gupta constexpr const char* ldapCreateInterface = 356973a582SRatan Gupta "xyz.openbmc_project.User.Ldap.Create"; 366973a582SRatan Gupta constexpr const char* ldapEnableInterface = "xyz.openbmc_project.Object.Enable"; 376973a582SRatan Gupta constexpr const char* dbusObjManagerIntf = "org.freedesktop.DBus.ObjectManager"; 386973a582SRatan Gupta constexpr const char* propertyInterface = "org.freedesktop.DBus.Properties"; 396973a582SRatan Gupta constexpr const char* mapperBusName = "xyz.openbmc_project.ObjectMapper"; 406973a582SRatan Gupta constexpr const char* mapperObjectPath = "/xyz/openbmc_project/object_mapper"; 416973a582SRatan Gupta constexpr const char* mapperIntf = "xyz.openbmc_project.ObjectMapper"; 426973a582SRatan Gupta 436973a582SRatan Gupta struct LDAPConfigData 446973a582SRatan Gupta { 456973a582SRatan Gupta std::string uri{}; 466973a582SRatan Gupta std::string bindDN{}; 476973a582SRatan Gupta std::string baseDN{}; 486973a582SRatan Gupta std::string searchScope{}; 496973a582SRatan Gupta std::string serverType{}; 506973a582SRatan Gupta bool serviceEnabled = false; 516973a582SRatan Gupta std::string userNameAttribute{}; 526973a582SRatan Gupta std::string groupAttribute{}; 536973a582SRatan Gupta }; 546973a582SRatan Gupta 55b9b2e0b2SEd Tanous using ManagedObjectType = std::vector<std::pair< 56b9b2e0b2SEd Tanous sdbusplus::message::object_path, 57b9b2e0b2SEd Tanous boost::container::flat_map< 58abf2add6SEd Tanous std::string, boost::container::flat_map< 59abf2add6SEd Tanous std::string, std::variant<bool, std::string>>>>>; 606973a582SRatan Gupta using GetObjectType = 616973a582SRatan Gupta std::vector<std::pair<std::string, std::vector<std::string>>>; 6284e12cb7SAppaRao Puli 63ae29b8c4SAdriana Kobylak inline std::string getPrivilegeFromRoleId(std::string_view role) 6484e12cb7SAppaRao Puli { 6584e12cb7SAppaRao Puli if (role == "priv-admin") 6684e12cb7SAppaRao Puli { 6784e12cb7SAppaRao Puli return "Administrator"; 6884e12cb7SAppaRao Puli } 6984e12cb7SAppaRao Puli else if (role == "priv-callback") 7084e12cb7SAppaRao Puli { 7184e12cb7SAppaRao Puli return "Callback"; 7284e12cb7SAppaRao Puli } 7384e12cb7SAppaRao Puli else if (role == "priv-user") 7484e12cb7SAppaRao Puli { 7584e12cb7SAppaRao Puli return "User"; 7684e12cb7SAppaRao Puli } 7784e12cb7SAppaRao Puli else if (role == "priv-operator") 7884e12cb7SAppaRao Puli { 7984e12cb7SAppaRao Puli return "Operator"; 8084e12cb7SAppaRao Puli } 8184e12cb7SAppaRao Puli return ""; 8284e12cb7SAppaRao Puli } 83ae29b8c4SAdriana Kobylak inline std::string getRoleIdFromPrivilege(std::string_view role) 8484e12cb7SAppaRao Puli { 8584e12cb7SAppaRao Puli if (role == "Administrator") 8684e12cb7SAppaRao Puli { 8784e12cb7SAppaRao Puli return "priv-admin"; 8884e12cb7SAppaRao Puli } 8984e12cb7SAppaRao Puli else if (role == "Callback") 9084e12cb7SAppaRao Puli { 9184e12cb7SAppaRao Puli return "priv-callback"; 9284e12cb7SAppaRao Puli } 9384e12cb7SAppaRao Puli else if (role == "User") 9484e12cb7SAppaRao Puli { 9584e12cb7SAppaRao Puli return "priv-user"; 9684e12cb7SAppaRao Puli } 9784e12cb7SAppaRao Puli else if (role == "Operator") 9884e12cb7SAppaRao Puli { 9984e12cb7SAppaRao Puli return "priv-operator"; 10084e12cb7SAppaRao Puli } 10184e12cb7SAppaRao Puli return ""; 10284e12cb7SAppaRao Puli } 103b9b2e0b2SEd Tanous 1046973a582SRatan Gupta void parseLDAPConfigData(nlohmann::json& json_response, 1056973a582SRatan Gupta const LDAPConfigData& confData) 1066973a582SRatan Gupta { 1076973a582SRatan Gupta std::string service = "LDAPService"; 1086973a582SRatan Gupta json_response["LDAP"] = { 1096973a582SRatan Gupta {"AccountProviderType", service}, 1106973a582SRatan Gupta {"AccountProviderType@Redfish.AllowableValues", 1116973a582SRatan Gupta nlohmann::json::array({service})}, 1126973a582SRatan Gupta {"ServiceEnabled", confData.serviceEnabled}, 1136973a582SRatan Gupta {"ServiceAddresses", nlohmann::json::array({confData.uri})}, 1146973a582SRatan Gupta {"Authentication", 1156973a582SRatan Gupta {{"AuthenticationType", "UsernameAndPassword"}, 1166973a582SRatan Gupta {"AuthenticationType@Redfish.AllowableValues", 1176973a582SRatan Gupta nlohmann::json::array({"UsernameAndPassword"})}, 1186973a582SRatan Gupta {"Username", confData.bindDN}, 1196973a582SRatan Gupta {"Password", nullptr}}}, 1206973a582SRatan Gupta {"LDAPService", 1216973a582SRatan Gupta {{"SearchSettings", 1226973a582SRatan Gupta {{"BaseDistinguishedNames", 1236973a582SRatan Gupta nlohmann::json::array({confData.baseDN})}, 1246973a582SRatan Gupta {"UsernameAttribute", confData.userNameAttribute}, 1256973a582SRatan Gupta {"GroupsAttribute", confData.groupAttribute}}}}}, 1266973a582SRatan Gupta }; 1276973a582SRatan Gupta } 1286973a582SRatan Gupta 1296973a582SRatan Gupta /** 1306973a582SRatan Gupta * Function that retrieves all properties for LDAP config object 1316973a582SRatan Gupta * into JSON 1326973a582SRatan Gupta */ 1336973a582SRatan Gupta template <typename CallbackFunc> 1346973a582SRatan Gupta inline void getLDAPConfigData(const std::string& ldapType, 1356973a582SRatan Gupta CallbackFunc&& callback) 1366973a582SRatan Gupta { 1376973a582SRatan Gupta auto getConfig = [callback, 1386973a582SRatan Gupta ldapType](const boost::system::error_code error_code, 1396973a582SRatan Gupta const ManagedObjectType& ldapObjects) { 1406973a582SRatan Gupta LDAPConfigData confData{}; 1416973a582SRatan Gupta if (error_code) 1426973a582SRatan Gupta { 1436973a582SRatan Gupta callback(false, confData); 1446973a582SRatan Gupta BMCWEB_LOG_ERROR << "D-Bus responses error: " << error_code; 1456973a582SRatan Gupta return; 1466973a582SRatan Gupta } 1476973a582SRatan Gupta std::string ldapConfigObjectStr = std::string(ldapConfigObject); 1486973a582SRatan Gupta std::string ldapEnableInterfaceStr = std::string(ldapEnableInterface); 1496973a582SRatan Gupta std::string ldapConfigInterfaceStr = std::string(ldapConfigInterface); 1506973a582SRatan Gupta for (const auto& object : ldapObjects) 1516973a582SRatan Gupta { 1526973a582SRatan Gupta if (object.first == ldapConfigObjectStr) 1536973a582SRatan Gupta { 1546973a582SRatan Gupta for (const auto& interface : object.second) 1556973a582SRatan Gupta { 1566973a582SRatan Gupta if (interface.first == ldapEnableInterfaceStr) 1576973a582SRatan Gupta { 1586973a582SRatan Gupta // rest of the properties are string. 1596973a582SRatan Gupta for (const auto& property : interface.second) 1606973a582SRatan Gupta { 1616973a582SRatan Gupta if (property.first == "Enabled") 1626973a582SRatan Gupta { 1636973a582SRatan Gupta const bool* value = 1646973a582SRatan Gupta std::get_if<bool>(&property.second); 1656973a582SRatan Gupta if (value == nullptr) 1666973a582SRatan Gupta { 1676973a582SRatan Gupta continue; 1686973a582SRatan Gupta } 1696973a582SRatan Gupta confData.serviceEnabled = *value; 1706973a582SRatan Gupta break; 1716973a582SRatan Gupta } 1726973a582SRatan Gupta } 1736973a582SRatan Gupta } 1746973a582SRatan Gupta else if (interface.first == ldapConfigInterfaceStr) 1756973a582SRatan Gupta { 1766973a582SRatan Gupta 1776973a582SRatan Gupta for (const auto& property : interface.second) 1786973a582SRatan Gupta { 1796973a582SRatan Gupta const std::string* value = 1806973a582SRatan Gupta std::get_if<std::string>(&property.second); 1816973a582SRatan Gupta if (value == nullptr) 1826973a582SRatan Gupta { 1836973a582SRatan Gupta continue; 1846973a582SRatan Gupta } 1856973a582SRatan Gupta if (property.first == "LDAPServerURI") 1866973a582SRatan Gupta { 1876973a582SRatan Gupta confData.uri = *value; 1886973a582SRatan Gupta } 1896973a582SRatan Gupta else if (property.first == "LDAPBindDN") 1906973a582SRatan Gupta { 1916973a582SRatan Gupta confData.bindDN = *value; 1926973a582SRatan Gupta } 1936973a582SRatan Gupta else if (property.first == "LDAPBaseDN") 1946973a582SRatan Gupta { 1956973a582SRatan Gupta confData.baseDN = *value; 1966973a582SRatan Gupta } 1976973a582SRatan Gupta else if (property.first == "LDAPSearchScope") 1986973a582SRatan Gupta { 1996973a582SRatan Gupta confData.searchScope = *value; 2006973a582SRatan Gupta } 2016973a582SRatan Gupta else if (property.first == "LDAPType") 2026973a582SRatan Gupta { 2036973a582SRatan Gupta confData.serverType = *value; 2046973a582SRatan Gupta } 2056973a582SRatan Gupta else if (property.first == "GroupNameAttribute") 2066973a582SRatan Gupta { 2076973a582SRatan Gupta confData.groupAttribute = *value; 2086973a582SRatan Gupta } 2096973a582SRatan Gupta else if (property.first == "UserNameAttribute") 2106973a582SRatan Gupta { 2116973a582SRatan Gupta confData.userNameAttribute = *value; 2126973a582SRatan Gupta } 2136973a582SRatan Gupta } 2146973a582SRatan Gupta } 2156973a582SRatan Gupta } 2166973a582SRatan Gupta 2176973a582SRatan Gupta callback(true, confData); 2186973a582SRatan Gupta break; 2196973a582SRatan Gupta } 2206973a582SRatan Gupta } 2216973a582SRatan Gupta }; 2226973a582SRatan Gupta auto getServiceName = [callback, getConfig(std::move(getConfig))]( 2236973a582SRatan Gupta const boost::system::error_code ec, 2246973a582SRatan Gupta const GetObjectType& resp) { 2256973a582SRatan Gupta LDAPConfigData confData{}; 2266973a582SRatan Gupta if (ec || resp.empty()) 2276973a582SRatan Gupta { 2286973a582SRatan Gupta BMCWEB_LOG_ERROR 2296973a582SRatan Gupta << "DBUS response error during getting of service name: " << ec; 2306973a582SRatan Gupta callback(false, confData); 2316973a582SRatan Gupta return; 2326973a582SRatan Gupta } 2336973a582SRatan Gupta std::string service = resp.begin()->first; 2346973a582SRatan Gupta crow::connections::systemBus->async_method_call( 2356973a582SRatan Gupta std::move(getConfig), service, ldapRootObject, dbusObjManagerIntf, 2366973a582SRatan Gupta "GetManagedObjects"); 2376973a582SRatan Gupta }; 2386973a582SRatan Gupta 2396973a582SRatan Gupta const std::array<std::string, 2> interfaces = {ldapEnableInterface, 2406973a582SRatan Gupta ldapConfigInterface}; 2416973a582SRatan Gupta 2426973a582SRatan Gupta crow::connections::systemBus->async_method_call( 2436973a582SRatan Gupta std::move(getServiceName), mapperBusName, mapperObjectPath, mapperIntf, 2446973a582SRatan Gupta "GetObject", ldapConfigObject, interfaces); 2456973a582SRatan Gupta } 2466973a582SRatan Gupta 2471abe55efSEd Tanous class AccountService : public Node 2481abe55efSEd Tanous { 24988d16c9aSLewanczyk, Dawid public: 2501abe55efSEd Tanous AccountService(CrowApp& app) : Node(app, "/redfish/v1/AccountService/") 2511abe55efSEd Tanous { 2523ebd75f7SEd Tanous entityPrivileges = { 2534b1b8683SBorawski.Lukasz {boost::beast::http::verb::get, 2544b1b8683SBorawski.Lukasz {{"ConfigureUsers"}, {"ConfigureManager"}}}, 255e0d918bcSEd Tanous {boost::beast::http::verb::head, {{"Login"}}}, 256e0d918bcSEd Tanous {boost::beast::http::verb::patch, {{"ConfigureUsers"}}}, 257e0d918bcSEd Tanous {boost::beast::http::verb::put, {{"ConfigureUsers"}}}, 258e0d918bcSEd Tanous {boost::beast::http::verb::delete_, {{"ConfigureUsers"}}}, 259e0d918bcSEd Tanous {boost::beast::http::verb::post, {{"ConfigureUsers"}}}}; 26088d16c9aSLewanczyk, Dawid } 26188d16c9aSLewanczyk, Dawid 26288d16c9aSLewanczyk, Dawid private: 263*8a07d286SRatan Gupta /** 264*8a07d286SRatan Gupta * @brief parses the authentication section under the LDAP 265*8a07d286SRatan Gupta * @param input JSON data 266*8a07d286SRatan Gupta * @param asyncResp pointer to the JSON response 267*8a07d286SRatan Gupta * @param userName userName to be filled from the given JSON. 268*8a07d286SRatan Gupta * @param password password to be filled from the given JSON. 269*8a07d286SRatan Gupta */ 270*8a07d286SRatan Gupta void 271*8a07d286SRatan Gupta parseLDAPAuthenticationJson(nlohmann::json input, 272*8a07d286SRatan Gupta const std::shared_ptr<AsyncResp>& asyncResp, 273*8a07d286SRatan Gupta std::optional<std::string>& username, 274*8a07d286SRatan Gupta std::optional<std::string>& password) 275*8a07d286SRatan Gupta { 276*8a07d286SRatan Gupta std::optional<std::string> authType; 277*8a07d286SRatan Gupta 278*8a07d286SRatan Gupta if (!json_util::readJson(input, asyncResp->res, "AuthenticationType", 279*8a07d286SRatan Gupta authType, "Username", username, "Password", 280*8a07d286SRatan Gupta password)) 281*8a07d286SRatan Gupta { 282*8a07d286SRatan Gupta return; 283*8a07d286SRatan Gupta } 284*8a07d286SRatan Gupta if (!authType) 285*8a07d286SRatan Gupta { 286*8a07d286SRatan Gupta return; 287*8a07d286SRatan Gupta } 288*8a07d286SRatan Gupta if (*authType != "UsernameAndPassword") 289*8a07d286SRatan Gupta { 290*8a07d286SRatan Gupta messages::propertyValueNotInList(asyncResp->res, *authType, 291*8a07d286SRatan Gupta "AuthenticationType"); 292*8a07d286SRatan Gupta return; 293*8a07d286SRatan Gupta } 294*8a07d286SRatan Gupta } 295*8a07d286SRatan Gupta /** 296*8a07d286SRatan Gupta * @brief parses the LDAPService section under the LDAP 297*8a07d286SRatan Gupta * @param input JSON data 298*8a07d286SRatan Gupta * @param asyncResp pointer to the JSON response 299*8a07d286SRatan Gupta * @param baseDNList baseDN to be filled from the given JSON. 300*8a07d286SRatan Gupta * @param userNameAttribute userName to be filled from the given JSON. 301*8a07d286SRatan Gupta * @param groupaAttribute password to be filled from the given JSON. 302*8a07d286SRatan Gupta */ 303*8a07d286SRatan Gupta 304*8a07d286SRatan Gupta void parseLDAPServiceJson( 305*8a07d286SRatan Gupta nlohmann::json input, const std::shared_ptr<AsyncResp>& asyncResp, 306*8a07d286SRatan Gupta std::optional<std::vector<std::string>>& baseDNList, 307*8a07d286SRatan Gupta std::optional<std::string>& userNameAttribute, 308*8a07d286SRatan Gupta std::optional<std::string>& groupsAttribute) 309*8a07d286SRatan Gupta { 310*8a07d286SRatan Gupta std::optional<nlohmann::json> searchSettings; 311*8a07d286SRatan Gupta 312*8a07d286SRatan Gupta if (!json_util::readJson(input, asyncResp->res, "SearchSettings", 313*8a07d286SRatan Gupta searchSettings)) 314*8a07d286SRatan Gupta { 315*8a07d286SRatan Gupta return; 316*8a07d286SRatan Gupta } 317*8a07d286SRatan Gupta if (!searchSettings) 318*8a07d286SRatan Gupta { 319*8a07d286SRatan Gupta return; 320*8a07d286SRatan Gupta } 321*8a07d286SRatan Gupta if (!json_util::readJson(*searchSettings, asyncResp->res, 322*8a07d286SRatan Gupta "BaseDistinguishedNames", baseDNList, 323*8a07d286SRatan Gupta "UsernameAttribute", userNameAttribute, 324*8a07d286SRatan Gupta "GroupsAttribute", groupsAttribute)) 325*8a07d286SRatan Gupta { 326*8a07d286SRatan Gupta return; 327*8a07d286SRatan Gupta } 328*8a07d286SRatan Gupta } 329*8a07d286SRatan Gupta /** 330*8a07d286SRatan Gupta * @brief updates the LDAP server address and updates the 331*8a07d286SRatan Gupta json response with the new value. 332*8a07d286SRatan Gupta * @param serviceAddressList address to be updated. 333*8a07d286SRatan Gupta * @param asyncResp pointer to the JSON response 334*8a07d286SRatan Gupta * @param ldapServerElementName Type of LDAP 335*8a07d286SRatan Gupta server(openLDAP/ActiveDirectory) 336*8a07d286SRatan Gupta */ 337*8a07d286SRatan Gupta 338*8a07d286SRatan Gupta void handleServiceAddressPatch( 339*8a07d286SRatan Gupta const std::vector<std::string>& serviceAddressList, 340*8a07d286SRatan Gupta const std::shared_ptr<AsyncResp>& asyncResp, 341*8a07d286SRatan Gupta const std::string& ldapServerElementName, 342*8a07d286SRatan Gupta const std::string& ldapConfigObject) 343*8a07d286SRatan Gupta { 344*8a07d286SRatan Gupta crow::connections::systemBus->async_method_call( 345*8a07d286SRatan Gupta [asyncResp, ldapServerElementName, 346*8a07d286SRatan Gupta serviceAddressList](const boost::system::error_code ec) { 347*8a07d286SRatan Gupta if (ec) 348*8a07d286SRatan Gupta { 349*8a07d286SRatan Gupta BMCWEB_LOG_DEBUG 350*8a07d286SRatan Gupta << "Error Occured in updating the service address"; 351*8a07d286SRatan Gupta messages::internalError(asyncResp->res); 352*8a07d286SRatan Gupta return; 353*8a07d286SRatan Gupta } 354*8a07d286SRatan Gupta std::vector<std::string> modifiedserviceAddressList = { 355*8a07d286SRatan Gupta serviceAddressList.front()}; 356*8a07d286SRatan Gupta asyncResp->res 357*8a07d286SRatan Gupta .jsonValue[ldapServerElementName]["ServiceAddresses"] = 358*8a07d286SRatan Gupta modifiedserviceAddressList; 359*8a07d286SRatan Gupta if ((serviceAddressList).size() > 1) 360*8a07d286SRatan Gupta { 361*8a07d286SRatan Gupta messages::propertyValueModified(asyncResp->res, 362*8a07d286SRatan Gupta "ServiceAddresses", 363*8a07d286SRatan Gupta serviceAddressList.front()); 364*8a07d286SRatan Gupta } 365*8a07d286SRatan Gupta BMCWEB_LOG_DEBUG << "Updated the service address"; 366*8a07d286SRatan Gupta }, 367*8a07d286SRatan Gupta ldapDbusService, ldapConfigObject, propertyInterface, "Set", 368*8a07d286SRatan Gupta ldapConfigInterface, "LDAPServerURI", 369*8a07d286SRatan Gupta std::variant<std::string>(serviceAddressList.front())); 370*8a07d286SRatan Gupta } 371*8a07d286SRatan Gupta /** 372*8a07d286SRatan Gupta * @brief updates the LDAP Bind DN and updates the 373*8a07d286SRatan Gupta json response with the new value. 374*8a07d286SRatan Gupta * @param username name of the user which needs to be updated. 375*8a07d286SRatan Gupta * @param asyncResp pointer to the JSON response 376*8a07d286SRatan Gupta * @param ldapServerElementName Type of LDAP 377*8a07d286SRatan Gupta server(openLDAP/ActiveDirectory) 378*8a07d286SRatan Gupta */ 379*8a07d286SRatan Gupta 380*8a07d286SRatan Gupta void handleUserNamePatch(const std::string& username, 381*8a07d286SRatan Gupta const std::shared_ptr<AsyncResp>& asyncResp, 382*8a07d286SRatan Gupta const std::string& ldapServerElementName, 383*8a07d286SRatan Gupta const std::string& ldapConfigObject) 384*8a07d286SRatan Gupta { 385*8a07d286SRatan Gupta crow::connections::systemBus->async_method_call( 386*8a07d286SRatan Gupta [asyncResp, username, 387*8a07d286SRatan Gupta ldapServerElementName](const boost::system::error_code ec) { 388*8a07d286SRatan Gupta if (ec) 389*8a07d286SRatan Gupta { 390*8a07d286SRatan Gupta BMCWEB_LOG_DEBUG 391*8a07d286SRatan Gupta << "Error occured in updating the username"; 392*8a07d286SRatan Gupta messages::internalError(asyncResp->res); 393*8a07d286SRatan Gupta return; 394*8a07d286SRatan Gupta } 395*8a07d286SRatan Gupta asyncResp->res.jsonValue[ldapServerElementName] 396*8a07d286SRatan Gupta ["Authentication"]["Username"] = 397*8a07d286SRatan Gupta username; 398*8a07d286SRatan Gupta BMCWEB_LOG_DEBUG << "Updated the username"; 399*8a07d286SRatan Gupta }, 400*8a07d286SRatan Gupta ldapDbusService, ldapConfigObject, propertyInterface, "Set", 401*8a07d286SRatan Gupta ldapConfigInterface, "LDAPBindDN", 402*8a07d286SRatan Gupta std::variant<std::string>(username)); 403*8a07d286SRatan Gupta } 404*8a07d286SRatan Gupta 405*8a07d286SRatan Gupta /** 406*8a07d286SRatan Gupta * @brief updates the LDAP password 407*8a07d286SRatan Gupta * @param password : ldap password which needs to be updated. 408*8a07d286SRatan Gupta * @param asyncResp pointer to the JSON response 409*8a07d286SRatan Gupta * @param ldapServerElementName Type of LDAP 410*8a07d286SRatan Gupta * server(openLDAP/ActiveDirectory) 411*8a07d286SRatan Gupta */ 412*8a07d286SRatan Gupta 413*8a07d286SRatan Gupta void handlePasswordPatch(const std::string& password, 414*8a07d286SRatan Gupta const std::shared_ptr<AsyncResp>& asyncResp, 415*8a07d286SRatan Gupta const std::string& ldapServerElementName, 416*8a07d286SRatan Gupta const std::string& ldapConfigObject) 417*8a07d286SRatan Gupta { 418*8a07d286SRatan Gupta crow::connections::systemBus->async_method_call( 419*8a07d286SRatan Gupta [asyncResp, password, 420*8a07d286SRatan Gupta ldapServerElementName](const boost::system::error_code ec) { 421*8a07d286SRatan Gupta if (ec) 422*8a07d286SRatan Gupta { 423*8a07d286SRatan Gupta BMCWEB_LOG_DEBUG 424*8a07d286SRatan Gupta << "Error occured in updating the password"; 425*8a07d286SRatan Gupta messages::internalError(asyncResp->res); 426*8a07d286SRatan Gupta return; 427*8a07d286SRatan Gupta } 428*8a07d286SRatan Gupta asyncResp->res.jsonValue[ldapServerElementName] 429*8a07d286SRatan Gupta ["Authentication"]["Password"] = ""; 430*8a07d286SRatan Gupta BMCWEB_LOG_DEBUG << "Updated the password"; 431*8a07d286SRatan Gupta }, 432*8a07d286SRatan Gupta ldapDbusService, ldapConfigObject, propertyInterface, "Set", 433*8a07d286SRatan Gupta ldapConfigInterface, "LDAPBindDNPassword", 434*8a07d286SRatan Gupta std::variant<std::string>(password)); 435*8a07d286SRatan Gupta } 436*8a07d286SRatan Gupta 437*8a07d286SRatan Gupta /** 438*8a07d286SRatan Gupta * @brief updates the LDAP BaseDN and updates the 439*8a07d286SRatan Gupta json response with the new value. 440*8a07d286SRatan Gupta * @param baseDNList baseDN list which needs to be updated. 441*8a07d286SRatan Gupta * @param asyncResp pointer to the JSON response 442*8a07d286SRatan Gupta * @param ldapServerElementName Type of LDAP 443*8a07d286SRatan Gupta server(openLDAP/ActiveDirectory) 444*8a07d286SRatan Gupta */ 445*8a07d286SRatan Gupta 446*8a07d286SRatan Gupta void handleBaseDNPatch(const std::vector<std::string>& baseDNList, 447*8a07d286SRatan Gupta const std::shared_ptr<AsyncResp>& asyncResp, 448*8a07d286SRatan Gupta const std::string& ldapServerElementName, 449*8a07d286SRatan Gupta const std::string& ldapConfigObject) 450*8a07d286SRatan Gupta { 451*8a07d286SRatan Gupta crow::connections::systemBus->async_method_call( 452*8a07d286SRatan Gupta [asyncResp, baseDNList, 453*8a07d286SRatan Gupta ldapServerElementName](const boost::system::error_code ec) { 454*8a07d286SRatan Gupta if (ec) 455*8a07d286SRatan Gupta { 456*8a07d286SRatan Gupta BMCWEB_LOG_DEBUG << "Error Occured in Updating the base DN"; 457*8a07d286SRatan Gupta messages::internalError(asyncResp->res); 458*8a07d286SRatan Gupta return; 459*8a07d286SRatan Gupta } 460*8a07d286SRatan Gupta auto& serverTypeJson = 461*8a07d286SRatan Gupta asyncResp->res.jsonValue[ldapServerElementName]; 462*8a07d286SRatan Gupta auto& searchSettingsJson = 463*8a07d286SRatan Gupta serverTypeJson["LDAPService"]["SearchSettings"]; 464*8a07d286SRatan Gupta std::vector<std::string> modifiedBaseDNList = { 465*8a07d286SRatan Gupta baseDNList.front()}; 466*8a07d286SRatan Gupta searchSettingsJson["BaseDistinguishedNames"] = 467*8a07d286SRatan Gupta modifiedBaseDNList; 468*8a07d286SRatan Gupta if (baseDNList.size() > 1) 469*8a07d286SRatan Gupta { 470*8a07d286SRatan Gupta messages::propertyValueModified(asyncResp->res, 471*8a07d286SRatan Gupta "BaseDistinguishedNames", 472*8a07d286SRatan Gupta baseDNList.front()); 473*8a07d286SRatan Gupta } 474*8a07d286SRatan Gupta BMCWEB_LOG_DEBUG << "Updated the base DN"; 475*8a07d286SRatan Gupta }, 476*8a07d286SRatan Gupta ldapDbusService, ldapConfigObject, propertyInterface, "Set", 477*8a07d286SRatan Gupta ldapConfigInterface, "LDAPBaseDN", 478*8a07d286SRatan Gupta std::variant<std::string>(baseDNList.front())); 479*8a07d286SRatan Gupta } 480*8a07d286SRatan Gupta /** 481*8a07d286SRatan Gupta * @brief updates the LDAP user name attribute and updates the 482*8a07d286SRatan Gupta json response with the new value. 483*8a07d286SRatan Gupta * @param userNameAttribute attribute to be updated. 484*8a07d286SRatan Gupta * @param asyncResp pointer to the JSON response 485*8a07d286SRatan Gupta * @param ldapServerElementName Type of LDAP 486*8a07d286SRatan Gupta server(openLDAP/ActiveDirectory) 487*8a07d286SRatan Gupta */ 488*8a07d286SRatan Gupta 489*8a07d286SRatan Gupta void handleUserNameAttrPatch(const std::string& userNameAttribute, 490*8a07d286SRatan Gupta const std::shared_ptr<AsyncResp>& asyncResp, 491*8a07d286SRatan Gupta const std::string& ldapServerElementName, 492*8a07d286SRatan Gupta const std::string& ldapConfigObject) 493*8a07d286SRatan Gupta { 494*8a07d286SRatan Gupta crow::connections::systemBus->async_method_call( 495*8a07d286SRatan Gupta [asyncResp, userNameAttribute, 496*8a07d286SRatan Gupta ldapServerElementName](const boost::system::error_code ec) { 497*8a07d286SRatan Gupta if (ec) 498*8a07d286SRatan Gupta { 499*8a07d286SRatan Gupta BMCWEB_LOG_DEBUG << "Error Occured in Updating the " 500*8a07d286SRatan Gupta "username attribute"; 501*8a07d286SRatan Gupta messages::internalError(asyncResp->res); 502*8a07d286SRatan Gupta return; 503*8a07d286SRatan Gupta } 504*8a07d286SRatan Gupta auto& serverTypeJson = 505*8a07d286SRatan Gupta asyncResp->res.jsonValue[ldapServerElementName]; 506*8a07d286SRatan Gupta auto& searchSettingsJson = 507*8a07d286SRatan Gupta serverTypeJson["LDAPService"]["SearchSettings"]; 508*8a07d286SRatan Gupta searchSettingsJson["UsernameAttribute"] = userNameAttribute; 509*8a07d286SRatan Gupta BMCWEB_LOG_DEBUG << "Updated the user name attr."; 510*8a07d286SRatan Gupta }, 511*8a07d286SRatan Gupta ldapDbusService, ldapConfigObject, propertyInterface, "Set", 512*8a07d286SRatan Gupta ldapConfigInterface, "UserNameAttribute", 513*8a07d286SRatan Gupta std::variant<std::string>(userNameAttribute)); 514*8a07d286SRatan Gupta } 515*8a07d286SRatan Gupta /** 516*8a07d286SRatan Gupta * @brief updates the LDAP group attribute and updates the 517*8a07d286SRatan Gupta json response with the new value. 518*8a07d286SRatan Gupta * @param groupsAttribute attribute to be updated. 519*8a07d286SRatan Gupta * @param asyncResp pointer to the JSON response 520*8a07d286SRatan Gupta * @param ldapServerElementName Type of LDAP 521*8a07d286SRatan Gupta server(openLDAP/ActiveDirectory) 522*8a07d286SRatan Gupta */ 523*8a07d286SRatan Gupta 524*8a07d286SRatan Gupta void handleGroupNameAttrPatch(const std::string& groupsAttribute, 525*8a07d286SRatan Gupta const std::shared_ptr<AsyncResp>& asyncResp, 526*8a07d286SRatan Gupta const std::string& ldapServerElementName, 527*8a07d286SRatan Gupta const std::string& ldapConfigObject) 528*8a07d286SRatan Gupta { 529*8a07d286SRatan Gupta crow::connections::systemBus->async_method_call( 530*8a07d286SRatan Gupta [asyncResp, groupsAttribute, 531*8a07d286SRatan Gupta ldapServerElementName](const boost::system::error_code ec) { 532*8a07d286SRatan Gupta if (ec) 533*8a07d286SRatan Gupta { 534*8a07d286SRatan Gupta BMCWEB_LOG_DEBUG << "Error Occured in Updating the " 535*8a07d286SRatan Gupta "groupname attribute"; 536*8a07d286SRatan Gupta messages::internalError(asyncResp->res); 537*8a07d286SRatan Gupta return; 538*8a07d286SRatan Gupta } 539*8a07d286SRatan Gupta auto& serverTypeJson = 540*8a07d286SRatan Gupta asyncResp->res.jsonValue[ldapServerElementName]; 541*8a07d286SRatan Gupta auto& searchSettingsJson = 542*8a07d286SRatan Gupta serverTypeJson["LDAPService"]["SearchSettings"]; 543*8a07d286SRatan Gupta searchSettingsJson["GroupsAttribute"] = groupsAttribute; 544*8a07d286SRatan Gupta BMCWEB_LOG_DEBUG << "Updated the groupname attr"; 545*8a07d286SRatan Gupta }, 546*8a07d286SRatan Gupta ldapDbusService, ldapConfigObject, propertyInterface, "Set", 547*8a07d286SRatan Gupta ldapConfigInterface, "GroupNameAttribute", 548*8a07d286SRatan Gupta std::variant<std::string>(groupsAttribute)); 549*8a07d286SRatan Gupta } 550*8a07d286SRatan Gupta /** 551*8a07d286SRatan Gupta * @brief updates the LDAP service enable and updates the 552*8a07d286SRatan Gupta json response with the new value. 553*8a07d286SRatan Gupta * @param input JSON data. 554*8a07d286SRatan Gupta * @param asyncResp pointer to the JSON response 555*8a07d286SRatan Gupta * @param ldapServerElementName Type of LDAP 556*8a07d286SRatan Gupta server(openLDAP/ActiveDirectory) 557*8a07d286SRatan Gupta */ 558*8a07d286SRatan Gupta 559*8a07d286SRatan Gupta void handleServiceEnablePatch(bool serviceEnabled, 560*8a07d286SRatan Gupta const std::shared_ptr<AsyncResp>& asyncResp, 561*8a07d286SRatan Gupta const std::string& ldapServerElementName, 562*8a07d286SRatan Gupta const std::string& ldapConfigObject) 563*8a07d286SRatan Gupta { 564*8a07d286SRatan Gupta crow::connections::systemBus->async_method_call( 565*8a07d286SRatan Gupta [asyncResp, serviceEnabled, 566*8a07d286SRatan Gupta ldapServerElementName](const boost::system::error_code ec) { 567*8a07d286SRatan Gupta if (ec) 568*8a07d286SRatan Gupta { 569*8a07d286SRatan Gupta BMCWEB_LOG_DEBUG 570*8a07d286SRatan Gupta << "Error Occured in Updating the service enable"; 571*8a07d286SRatan Gupta messages::internalError(asyncResp->res); 572*8a07d286SRatan Gupta return; 573*8a07d286SRatan Gupta } 574*8a07d286SRatan Gupta asyncResp->res 575*8a07d286SRatan Gupta .jsonValue[ldapServerElementName]["ServiceEnabled"] = 576*8a07d286SRatan Gupta serviceEnabled; 577*8a07d286SRatan Gupta BMCWEB_LOG_DEBUG << "Updated Service enable = " 578*8a07d286SRatan Gupta << serviceEnabled; 579*8a07d286SRatan Gupta }, 580*8a07d286SRatan Gupta ldapDbusService, ldapConfigObject, propertyInterface, "Set", 581*8a07d286SRatan Gupta ldapEnableInterface, "Enabled", std::variant<bool>(serviceEnabled)); 582*8a07d286SRatan Gupta } 583*8a07d286SRatan Gupta 584*8a07d286SRatan Gupta /** 585*8a07d286SRatan Gupta * @brief Get the required values from the given JSON, validates the 586*8a07d286SRatan Gupta * value and create the LDAP config object. 587*8a07d286SRatan Gupta * @param input JSON data 588*8a07d286SRatan Gupta * @param asyncResp pointer to the JSON response 589*8a07d286SRatan Gupta * @param serverType Type of LDAP server(openLDAP/ActiveDirectory) 590*8a07d286SRatan Gupta */ 591*8a07d286SRatan Gupta 592*8a07d286SRatan Gupta void handleLDAPPatch(nlohmann::json& input, 593*8a07d286SRatan Gupta const std::shared_ptr<AsyncResp>& asyncResp, 594*8a07d286SRatan Gupta const crow::Request& req, 595*8a07d286SRatan Gupta const std::vector<std::string>& params, 596*8a07d286SRatan Gupta const std::string& serverType) 597*8a07d286SRatan Gupta { 598*8a07d286SRatan Gupta std::optional<nlohmann::json> authentication; 599*8a07d286SRatan Gupta std::optional<nlohmann::json> ldapService; 600*8a07d286SRatan Gupta std::optional<std::string> accountProviderType; 601*8a07d286SRatan Gupta std::optional<std::vector<std::string>> serviceAddressList; 602*8a07d286SRatan Gupta std::optional<bool> serviceEnabled; 603*8a07d286SRatan Gupta std::optional<std::vector<std::string>> baseDNList; 604*8a07d286SRatan Gupta std::optional<std::string> userNameAttribute; 605*8a07d286SRatan Gupta std::optional<std::string> groupsAttribute; 606*8a07d286SRatan Gupta std::optional<std::string> userName; 607*8a07d286SRatan Gupta std::optional<std::string> password; 608*8a07d286SRatan Gupta 609*8a07d286SRatan Gupta if (!json_util::readJson(input, asyncResp->res, "Authentication", 610*8a07d286SRatan Gupta authentication, "LDAPService", ldapService, 611*8a07d286SRatan Gupta "ServiceAddresses", serviceAddressList, 612*8a07d286SRatan Gupta "AccountProviderType", accountProviderType, 613*8a07d286SRatan Gupta "ServiceEnabled", serviceEnabled)) 614*8a07d286SRatan Gupta { 615*8a07d286SRatan Gupta return; 616*8a07d286SRatan Gupta } 617*8a07d286SRatan Gupta 618*8a07d286SRatan Gupta if (authentication) 619*8a07d286SRatan Gupta { 620*8a07d286SRatan Gupta parseLDAPAuthenticationJson(*authentication, asyncResp, userName, 621*8a07d286SRatan Gupta password); 622*8a07d286SRatan Gupta } 623*8a07d286SRatan Gupta if (ldapService) 624*8a07d286SRatan Gupta { 625*8a07d286SRatan Gupta parseLDAPServiceJson(*ldapService, asyncResp, baseDNList, 626*8a07d286SRatan Gupta userNameAttribute, groupsAttribute); 627*8a07d286SRatan Gupta } 628*8a07d286SRatan Gupta if (accountProviderType) 629*8a07d286SRatan Gupta { 630*8a07d286SRatan Gupta messages::propertyNotWritable(asyncResp->res, 631*8a07d286SRatan Gupta "AccountProviderType"); 632*8a07d286SRatan Gupta } 633*8a07d286SRatan Gupta if (serviceAddressList) 634*8a07d286SRatan Gupta { 635*8a07d286SRatan Gupta if ((*serviceAddressList).size() == 0) 636*8a07d286SRatan Gupta { 637*8a07d286SRatan Gupta messages::propertyValueNotInList(asyncResp->res, "[]", 638*8a07d286SRatan Gupta "ServiceAddress"); 639*8a07d286SRatan Gupta return; 640*8a07d286SRatan Gupta } 641*8a07d286SRatan Gupta } 642*8a07d286SRatan Gupta if (baseDNList) 643*8a07d286SRatan Gupta { 644*8a07d286SRatan Gupta if ((*baseDNList).size() == 0) 645*8a07d286SRatan Gupta { 646*8a07d286SRatan Gupta messages::propertyValueNotInList(asyncResp->res, "[]", 647*8a07d286SRatan Gupta "BaseDistinguishedNames"); 648*8a07d286SRatan Gupta return; 649*8a07d286SRatan Gupta } 650*8a07d286SRatan Gupta } 651*8a07d286SRatan Gupta 652*8a07d286SRatan Gupta // nothing to update, then return 653*8a07d286SRatan Gupta if (!userName && !password && !serviceAddressList && !baseDNList && 654*8a07d286SRatan Gupta !userNameAttribute && !groupsAttribute && !serviceEnabled) 655*8a07d286SRatan Gupta { 656*8a07d286SRatan Gupta return; 657*8a07d286SRatan Gupta } 658*8a07d286SRatan Gupta 659*8a07d286SRatan Gupta // Get the existing resource first then keep modifying 660*8a07d286SRatan Gupta // whenever any property gets updated. 661*8a07d286SRatan Gupta getLDAPConfigData( 662*8a07d286SRatan Gupta serverType, 663*8a07d286SRatan Gupta [this, asyncResp, userName, password, baseDNList, userNameAttribute, 664*8a07d286SRatan Gupta groupsAttribute, accountProviderType, serviceAddressList, 665*8a07d286SRatan Gupta serviceEnabled, 666*8a07d286SRatan Gupta serverType](bool success, LDAPConfigData confData) { 667*8a07d286SRatan Gupta if (!success) 668*8a07d286SRatan Gupta { 669*8a07d286SRatan Gupta messages::internalError(asyncResp->res); 670*8a07d286SRatan Gupta return; 671*8a07d286SRatan Gupta } 672*8a07d286SRatan Gupta parseLDAPConfigData(asyncResp->res.jsonValue, confData); 673*8a07d286SRatan Gupta if (confData.serviceEnabled) 674*8a07d286SRatan Gupta { 675*8a07d286SRatan Gupta // Disable the service first and update the rest of 676*8a07d286SRatan Gupta // the properties. 677*8a07d286SRatan Gupta handleServiceEnablePatch(false, asyncResp, serverType, 678*8a07d286SRatan Gupta ldapConfigObject); 679*8a07d286SRatan Gupta } 680*8a07d286SRatan Gupta 681*8a07d286SRatan Gupta if (serviceAddressList) 682*8a07d286SRatan Gupta { 683*8a07d286SRatan Gupta handleServiceAddressPatch(*serviceAddressList, asyncResp, 684*8a07d286SRatan Gupta serverType, ldapConfigObject); 685*8a07d286SRatan Gupta } 686*8a07d286SRatan Gupta if (userName) 687*8a07d286SRatan Gupta { 688*8a07d286SRatan Gupta handleUserNamePatch(*userName, asyncResp, serverType, 689*8a07d286SRatan Gupta ldapConfigObject); 690*8a07d286SRatan Gupta } 691*8a07d286SRatan Gupta if (password) 692*8a07d286SRatan Gupta { 693*8a07d286SRatan Gupta handlePasswordPatch(*password, asyncResp, serverType, 694*8a07d286SRatan Gupta ldapConfigObject); 695*8a07d286SRatan Gupta } 696*8a07d286SRatan Gupta 697*8a07d286SRatan Gupta if (baseDNList) 698*8a07d286SRatan Gupta { 699*8a07d286SRatan Gupta handleBaseDNPatch(*baseDNList, asyncResp, serverType, 700*8a07d286SRatan Gupta ldapConfigObject); 701*8a07d286SRatan Gupta } 702*8a07d286SRatan Gupta if (userNameAttribute) 703*8a07d286SRatan Gupta { 704*8a07d286SRatan Gupta handleUserNameAttrPatch(*userNameAttribute, asyncResp, 705*8a07d286SRatan Gupta serverType, ldapConfigObject); 706*8a07d286SRatan Gupta } 707*8a07d286SRatan Gupta if (groupsAttribute) 708*8a07d286SRatan Gupta { 709*8a07d286SRatan Gupta handleGroupNameAttrPatch(*groupsAttribute, asyncResp, 710*8a07d286SRatan Gupta serverType, ldapConfigObject); 711*8a07d286SRatan Gupta } 712*8a07d286SRatan Gupta if (serviceEnabled) 713*8a07d286SRatan Gupta { 714*8a07d286SRatan Gupta // if user has given the value as true then enable 715*8a07d286SRatan Gupta // the service. if user has given false then no-op 716*8a07d286SRatan Gupta // as service is already stopped. 717*8a07d286SRatan Gupta if (*serviceEnabled) 718*8a07d286SRatan Gupta { 719*8a07d286SRatan Gupta handleServiceEnablePatch(*serviceEnabled, asyncResp, 720*8a07d286SRatan Gupta serverType, ldapConfigObject); 721*8a07d286SRatan Gupta } 722*8a07d286SRatan Gupta } 723*8a07d286SRatan Gupta else 724*8a07d286SRatan Gupta { 725*8a07d286SRatan Gupta // if user has not given the service enabled value 726*8a07d286SRatan Gupta // then revert it to the same state as it was 727*8a07d286SRatan Gupta // before. 728*8a07d286SRatan Gupta handleServiceEnablePatch(confData.serviceEnabled, asyncResp, 729*8a07d286SRatan Gupta serverType, ldapConfigObject); 730*8a07d286SRatan Gupta } 731*8a07d286SRatan Gupta }); 732*8a07d286SRatan Gupta } 733*8a07d286SRatan Gupta 73455c7b7a2SEd Tanous void doGet(crow::Response& res, const crow::Request& req, 7351abe55efSEd Tanous const std::vector<std::string>& params) override 7361abe55efSEd Tanous { 7373d958bbcSAppaRao Puli auto asyncResp = std::make_shared<AsyncResp>(res); 7383d958bbcSAppaRao Puli res.jsonValue = { 7393d958bbcSAppaRao Puli {"@odata.context", "/redfish/v1/" 7403d958bbcSAppaRao Puli "$metadata#AccountService.AccountService"}, 7413d958bbcSAppaRao Puli {"@odata.id", "/redfish/v1/AccountService"}, 7423d958bbcSAppaRao Puli {"@odata.type", "#AccountService." 7436973a582SRatan Gupta "v1_3_1.AccountService"}, 7443d958bbcSAppaRao Puli {"Id", "AccountService"}, 7453d958bbcSAppaRao Puli {"Name", "Account Service"}, 7463d958bbcSAppaRao Puli {"Description", "Account Service"}, 7473d958bbcSAppaRao Puli {"ServiceEnabled", true}, 748343ff2e1SAppaRao Puli {"MaxPasswordLength", 20}, 7493d958bbcSAppaRao Puli {"Accounts", 7503d958bbcSAppaRao Puli {{"@odata.id", "/redfish/v1/AccountService/Accounts"}}}, 7513d958bbcSAppaRao Puli {"Roles", {{"@odata.id", "/redfish/v1/AccountService/Roles"}}}}; 7520f74e643SEd Tanous 7533d958bbcSAppaRao Puli crow::connections::systemBus->async_method_call( 7543d958bbcSAppaRao Puli [asyncResp]( 7553d958bbcSAppaRao Puli const boost::system::error_code ec, 7563d958bbcSAppaRao Puli const std::vector<std::pair< 757abf2add6SEd Tanous std::string, std::variant<uint32_t, uint16_t, uint8_t>>>& 7583d958bbcSAppaRao Puli propertiesList) { 7593d958bbcSAppaRao Puli if (ec) 7603d958bbcSAppaRao Puli { 7613d958bbcSAppaRao Puli messages::internalError(asyncResp->res); 7623d958bbcSAppaRao Puli return; 7633d958bbcSAppaRao Puli } 7643d958bbcSAppaRao Puli BMCWEB_LOG_DEBUG << "Got " << propertiesList.size() 7653d958bbcSAppaRao Puli << "properties for AccountService"; 7663d958bbcSAppaRao Puli for (const std::pair<std::string, 767abf2add6SEd Tanous std::variant<uint32_t, uint16_t, uint8_t>>& 7683d958bbcSAppaRao Puli property : propertiesList) 7693d958bbcSAppaRao Puli { 7703d958bbcSAppaRao Puli if (property.first == "MinPasswordLength") 7713d958bbcSAppaRao Puli { 7723d958bbcSAppaRao Puli const uint8_t* value = 773abf2add6SEd Tanous std::get_if<uint8_t>(&property.second); 7743d958bbcSAppaRao Puli if (value != nullptr) 7753d958bbcSAppaRao Puli { 7763d958bbcSAppaRao Puli asyncResp->res.jsonValue["MinPasswordLength"] = 7773d958bbcSAppaRao Puli *value; 7783d958bbcSAppaRao Puli } 7793d958bbcSAppaRao Puli } 7803d958bbcSAppaRao Puli if (property.first == "AccountUnlockTimeout") 7813d958bbcSAppaRao Puli { 7823d958bbcSAppaRao Puli const uint32_t* value = 783abf2add6SEd Tanous std::get_if<uint32_t>(&property.second); 7843d958bbcSAppaRao Puli if (value != nullptr) 7853d958bbcSAppaRao Puli { 7863d958bbcSAppaRao Puli asyncResp->res.jsonValue["AccountLockoutDuration"] = 7873d958bbcSAppaRao Puli *value; 7883d958bbcSAppaRao Puli } 7893d958bbcSAppaRao Puli } 7903d958bbcSAppaRao Puli if (property.first == "MaxLoginAttemptBeforeLockout") 7913d958bbcSAppaRao Puli { 7923d958bbcSAppaRao Puli const uint16_t* value = 793abf2add6SEd Tanous std::get_if<uint16_t>(&property.second); 7943d958bbcSAppaRao Puli if (value != nullptr) 7953d958bbcSAppaRao Puli { 7963d958bbcSAppaRao Puli asyncResp->res 7973d958bbcSAppaRao Puli .jsonValue["AccountLockoutThreshold"] = *value; 7983d958bbcSAppaRao Puli } 7993d958bbcSAppaRao Puli } 8003d958bbcSAppaRao Puli } 8013d958bbcSAppaRao Puli }, 8023d958bbcSAppaRao Puli "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user", 8033d958bbcSAppaRao Puli "org.freedesktop.DBus.Properties", "GetAll", 8043d958bbcSAppaRao Puli "xyz.openbmc_project.User.AccountPolicy"); 8056973a582SRatan Gupta 8066973a582SRatan Gupta std::string ldapType = "LDAP"; 8076973a582SRatan Gupta getLDAPConfigData( 8086973a582SRatan Gupta ldapType, 8096973a582SRatan Gupta [asyncResp, ldapType](bool success, LDAPConfigData& confData) { 8106973a582SRatan Gupta parseLDAPConfigData(asyncResp->res.jsonValue, confData); 8116973a582SRatan Gupta }); 8123d958bbcSAppaRao Puli } 8136973a582SRatan Gupta 8143d958bbcSAppaRao Puli void doPatch(crow::Response& res, const crow::Request& req, 8153d958bbcSAppaRao Puli const std::vector<std::string>& params) override 8163d958bbcSAppaRao Puli { 8173d958bbcSAppaRao Puli auto asyncResp = std::make_shared<AsyncResp>(res); 8183d958bbcSAppaRao Puli 8193d958bbcSAppaRao Puli std::optional<uint32_t> unlockTimeout; 8203d958bbcSAppaRao Puli std::optional<uint16_t> lockoutThreshold; 82119fb6e71SRatan Gupta std::optional<uint16_t> minPasswordLength; 82219fb6e71SRatan Gupta std::optional<uint16_t> maxPasswordLength; 823*8a07d286SRatan Gupta std::optional<nlohmann::json> ldapObject; 82419fb6e71SRatan Gupta 8253d958bbcSAppaRao Puli if (!json_util::readJson(req, res, "AccountLockoutDuration", 8263d958bbcSAppaRao Puli unlockTimeout, "AccountLockoutThreshold", 82719fb6e71SRatan Gupta lockoutThreshold, "MaxPasswordLength", 82819fb6e71SRatan Gupta maxPasswordLength, "MinPasswordLength", 82919fb6e71SRatan Gupta minPasswordLength)) 8303d958bbcSAppaRao Puli { 8313d958bbcSAppaRao Puli return; 8323d958bbcSAppaRao Puli } 83319fb6e71SRatan Gupta 83419fb6e71SRatan Gupta if (minPasswordLength) 83519fb6e71SRatan Gupta { 83619fb6e71SRatan Gupta messages::propertyNotWritable(asyncResp->res, "MinPasswordLength"); 83719fb6e71SRatan Gupta } 83819fb6e71SRatan Gupta 83919fb6e71SRatan Gupta if (maxPasswordLength) 84019fb6e71SRatan Gupta { 84119fb6e71SRatan Gupta messages::propertyNotWritable(asyncResp->res, "MaxPasswordLength"); 84219fb6e71SRatan Gupta } 84319fb6e71SRatan Gupta 844*8a07d286SRatan Gupta if (ldapObject) 845*8a07d286SRatan Gupta { 846*8a07d286SRatan Gupta handleLDAPPatch(*ldapObject, asyncResp, req, params, "LDAP"); 847*8a07d286SRatan Gupta } 848*8a07d286SRatan Gupta 8493d958bbcSAppaRao Puli if (unlockTimeout) 8503d958bbcSAppaRao Puli { 8513d958bbcSAppaRao Puli crow::connections::systemBus->async_method_call( 8523d958bbcSAppaRao Puli [asyncResp](const boost::system::error_code ec) { 8533d958bbcSAppaRao Puli if (ec) 8543d958bbcSAppaRao Puli { 8553d958bbcSAppaRao Puli messages::internalError(asyncResp->res); 8563d958bbcSAppaRao Puli return; 8573d958bbcSAppaRao Puli } 858add6133bSRatan Gupta messages::success(asyncResp->res); 8593d958bbcSAppaRao Puli }, 8603d958bbcSAppaRao Puli "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user", 8613d958bbcSAppaRao Puli "org.freedesktop.DBus.Properties", "Set", 8623d958bbcSAppaRao Puli "xyz.openbmc_project.User.AccountPolicy", 863abf2add6SEd Tanous "AccountUnlockTimeout", std::variant<uint32_t>(*unlockTimeout)); 8643d958bbcSAppaRao Puli } 8653d958bbcSAppaRao Puli if (lockoutThreshold) 8663d958bbcSAppaRao Puli { 8673d958bbcSAppaRao Puli crow::connections::systemBus->async_method_call( 8683d958bbcSAppaRao Puli [asyncResp](const boost::system::error_code ec) { 8693d958bbcSAppaRao Puli if (ec) 8703d958bbcSAppaRao Puli { 8713d958bbcSAppaRao Puli messages::internalError(asyncResp->res); 8723d958bbcSAppaRao Puli return; 8733d958bbcSAppaRao Puli } 874add6133bSRatan Gupta messages::success(asyncResp->res); 8753d958bbcSAppaRao Puli }, 8763d958bbcSAppaRao Puli "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user", 8773d958bbcSAppaRao Puli "org.freedesktop.DBus.Properties", "Set", 8783d958bbcSAppaRao Puli "xyz.openbmc_project.User.AccountPolicy", 8793d958bbcSAppaRao Puli "MaxLoginAttemptBeforeLockout", 880abf2add6SEd Tanous std::variant<uint16_t>(*lockoutThreshold)); 8813d958bbcSAppaRao Puli } 88288d16c9aSLewanczyk, Dawid } 88388d16c9aSLewanczyk, Dawid }; 884f00032dbSTanous 885b9b2e0b2SEd Tanous class AccountsCollection : public Node 886b9b2e0b2SEd Tanous { 887b9b2e0b2SEd Tanous public: 888b9b2e0b2SEd Tanous AccountsCollection(CrowApp& app) : 889b9b2e0b2SEd Tanous Node(app, "/redfish/v1/AccountService/Accounts/") 890b9b2e0b2SEd Tanous { 891b9b2e0b2SEd Tanous entityPrivileges = { 892b9b2e0b2SEd Tanous {boost::beast::http::verb::get, 893b9b2e0b2SEd Tanous {{"ConfigureUsers"}, {"ConfigureManager"}}}, 894b9b2e0b2SEd Tanous {boost::beast::http::verb::head, {{"Login"}}}, 895b9b2e0b2SEd Tanous {boost::beast::http::verb::patch, {{"ConfigureUsers"}}}, 896b9b2e0b2SEd Tanous {boost::beast::http::verb::put, {{"ConfigureUsers"}}}, 897b9b2e0b2SEd Tanous {boost::beast::http::verb::delete_, {{"ConfigureUsers"}}}, 898b9b2e0b2SEd Tanous {boost::beast::http::verb::post, {{"ConfigureUsers"}}}}; 899b9b2e0b2SEd Tanous } 900b9b2e0b2SEd Tanous 901b9b2e0b2SEd Tanous private: 902b9b2e0b2SEd Tanous void doGet(crow::Response& res, const crow::Request& req, 903b9b2e0b2SEd Tanous const std::vector<std::string>& params) override 904b9b2e0b2SEd Tanous { 905b9b2e0b2SEd Tanous auto asyncResp = std::make_shared<AsyncResp>(res); 9060f74e643SEd Tanous res.jsonValue = {{"@odata.context", 9070f74e643SEd Tanous "/redfish/v1/" 9080f74e643SEd Tanous "$metadata#ManagerAccountCollection." 9090f74e643SEd Tanous "ManagerAccountCollection"}, 9100f74e643SEd Tanous {"@odata.id", "/redfish/v1/AccountService/Accounts"}, 9110f74e643SEd Tanous {"@odata.type", "#ManagerAccountCollection." 9120f74e643SEd Tanous "ManagerAccountCollection"}, 9130f74e643SEd Tanous {"Name", "Accounts Collection"}, 9140f74e643SEd Tanous {"Description", "BMC User Accounts"}}; 9150f74e643SEd Tanous 916b9b2e0b2SEd Tanous crow::connections::systemBus->async_method_call( 917b9b2e0b2SEd Tanous [asyncResp](const boost::system::error_code ec, 918b9b2e0b2SEd Tanous const ManagedObjectType& users) { 919b9b2e0b2SEd Tanous if (ec) 920b9b2e0b2SEd Tanous { 921f12894f8SJason M. Bills messages::internalError(asyncResp->res); 922b9b2e0b2SEd Tanous return; 923b9b2e0b2SEd Tanous } 924b9b2e0b2SEd Tanous 925b9b2e0b2SEd Tanous nlohmann::json& memberArray = 926b9b2e0b2SEd Tanous asyncResp->res.jsonValue["Members"]; 927b9b2e0b2SEd Tanous memberArray = nlohmann::json::array(); 928b9b2e0b2SEd Tanous 929b9b2e0b2SEd Tanous asyncResp->res.jsonValue["Members@odata.count"] = users.size(); 930b9b2e0b2SEd Tanous for (auto& user : users) 931b9b2e0b2SEd Tanous { 932b9b2e0b2SEd Tanous const std::string& path = 933b9b2e0b2SEd Tanous static_cast<const std::string&>(user.first); 934b9b2e0b2SEd Tanous std::size_t lastIndex = path.rfind("/"); 935b9b2e0b2SEd Tanous if (lastIndex == std::string::npos) 936b9b2e0b2SEd Tanous { 937b9b2e0b2SEd Tanous lastIndex = 0; 938b9b2e0b2SEd Tanous } 939b9b2e0b2SEd Tanous else 940b9b2e0b2SEd Tanous { 941b9b2e0b2SEd Tanous lastIndex += 1; 942b9b2e0b2SEd Tanous } 943b9b2e0b2SEd Tanous memberArray.push_back( 944b9b2e0b2SEd Tanous {{"@odata.id", "/redfish/v1/AccountService/Accounts/" + 945b9b2e0b2SEd Tanous path.substr(lastIndex)}}); 946b9b2e0b2SEd Tanous } 947b9b2e0b2SEd Tanous }, 948b9b2e0b2SEd Tanous "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user", 949b9b2e0b2SEd Tanous "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 950b9b2e0b2SEd Tanous } 95104ae99ecSEd Tanous void doPost(crow::Response& res, const crow::Request& req, 95204ae99ecSEd Tanous const std::vector<std::string>& params) override 95304ae99ecSEd Tanous { 95404ae99ecSEd Tanous auto asyncResp = std::make_shared<AsyncResp>(res); 95504ae99ecSEd Tanous 9569712f8acSEd Tanous std::string username; 9579712f8acSEd Tanous std::string password; 958a24526dcSEd Tanous std::optional<std::string> roleId("User"); 959a24526dcSEd Tanous std::optional<bool> enabled = true; 9609712f8acSEd Tanous if (!json_util::readJson(req, res, "UserName", username, "Password", 9619712f8acSEd Tanous password, "RoleId", roleId, "Enabled", 9629712f8acSEd Tanous enabled)) 96304ae99ecSEd Tanous { 96404ae99ecSEd Tanous return; 96504ae99ecSEd Tanous } 96604ae99ecSEd Tanous 96784e12cb7SAppaRao Puli std::string priv = getRoleIdFromPrivilege(*roleId); 96884e12cb7SAppaRao Puli if (priv.empty()) 96904ae99ecSEd Tanous { 970f12894f8SJason M. Bills messages::propertyValueNotInList(asyncResp->res, *roleId, "RoleId"); 97104ae99ecSEd Tanous return; 97204ae99ecSEd Tanous } 9739712f8acSEd Tanous roleId = priv; 97404ae99ecSEd Tanous 97504ae99ecSEd Tanous crow::connections::systemBus->async_method_call( 9769712f8acSEd Tanous [asyncResp, username, password{std::move(password)}]( 97704ae99ecSEd Tanous const boost::system::error_code ec) { 97804ae99ecSEd Tanous if (ec) 97904ae99ecSEd Tanous { 98004ae99ecSEd Tanous messages::resourceAlreadyExists( 981f12894f8SJason M. Bills asyncResp->res, "#ManagerAccount.v1_0_3.ManagerAccount", 982f12894f8SJason M. Bills "UserName", username); 98304ae99ecSEd Tanous return; 98404ae99ecSEd Tanous } 98504ae99ecSEd Tanous 98604ae99ecSEd Tanous if (!pamUpdatePassword(username, password)) 98704ae99ecSEd Tanous { 98804ae99ecSEd Tanous // At this point we have a user that's been created, but the 98904ae99ecSEd Tanous // password set failed. Something is wrong, so delete the 99004ae99ecSEd Tanous // user that we've already created 99104ae99ecSEd Tanous crow::connections::systemBus->async_method_call( 99204ae99ecSEd Tanous [asyncResp](const boost::system::error_code ec) { 99304ae99ecSEd Tanous if (ec) 99404ae99ecSEd Tanous { 995f12894f8SJason M. Bills messages::internalError(asyncResp->res); 99604ae99ecSEd Tanous return; 99704ae99ecSEd Tanous } 99804ae99ecSEd Tanous 999f12894f8SJason M. Bills messages::invalidObject(asyncResp->res, "Password"); 100004ae99ecSEd Tanous }, 100104ae99ecSEd Tanous "xyz.openbmc_project.User.Manager", 100204ae99ecSEd Tanous "/xyz/openbmc_project/user/" + username, 100304ae99ecSEd Tanous "xyz.openbmc_project.Object.Delete", "Delete"); 100404ae99ecSEd Tanous 100504ae99ecSEd Tanous BMCWEB_LOG_ERROR << "pamUpdatePassword Failed"; 100604ae99ecSEd Tanous return; 100704ae99ecSEd Tanous } 100804ae99ecSEd Tanous 1009f12894f8SJason M. Bills messages::created(asyncResp->res); 101004ae99ecSEd Tanous asyncResp->res.addHeader( 101104ae99ecSEd Tanous "Location", 101204ae99ecSEd Tanous "/redfish/v1/AccountService/Accounts/" + username); 101304ae99ecSEd Tanous }, 101404ae99ecSEd Tanous "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user", 10159712f8acSEd Tanous "xyz.openbmc_project.User.Manager", "CreateUser", username, 101604ae99ecSEd Tanous std::array<const char*, 4>{"ipmi", "redfish", "ssh", "web"}, 10179712f8acSEd Tanous *roleId, *enabled); 101804ae99ecSEd Tanous } 1019b9b2e0b2SEd Tanous }; 1020b9b2e0b2SEd Tanous 1021a840879dSEd Tanous template <typename Callback> 1022a840879dSEd Tanous inline void checkDbusPathExists(const std::string& path, Callback&& callback) 1023a840879dSEd Tanous { 1024a840879dSEd Tanous using GetObjectType = 1025a840879dSEd Tanous std::vector<std::pair<std::string, std::vector<std::string>>>; 1026a840879dSEd Tanous 1027a840879dSEd Tanous crow::connections::systemBus->async_method_call( 1028a840879dSEd Tanous [callback{std::move(callback)}](const boost::system::error_code ec, 1029a840879dSEd Tanous const GetObjectType& object_names) { 103084e12cb7SAppaRao Puli callback(!ec && object_names.size() != 0); 1031a840879dSEd Tanous }, 1032a840879dSEd Tanous "xyz.openbmc_project.ObjectMapper", 1033a840879dSEd Tanous "/xyz/openbmc_project/object_mapper", 1034a840879dSEd Tanous "xyz.openbmc_project.ObjectMapper", "GetObject", path, 1035a840879dSEd Tanous std::array<std::string, 0>()); 1036a840879dSEd Tanous } 1037a840879dSEd Tanous 1038b9b2e0b2SEd Tanous class ManagerAccount : public Node 1039b9b2e0b2SEd Tanous { 1040b9b2e0b2SEd Tanous public: 1041b9b2e0b2SEd Tanous ManagerAccount(CrowApp& app) : 1042b9b2e0b2SEd Tanous Node(app, "/redfish/v1/AccountService/Accounts/<str>/", std::string()) 1043b9b2e0b2SEd Tanous { 1044b9b2e0b2SEd Tanous entityPrivileges = { 1045b9b2e0b2SEd Tanous {boost::beast::http::verb::get, 1046b9b2e0b2SEd Tanous {{"ConfigureUsers"}, {"ConfigureManager"}, {"ConfigureSelf"}}}, 1047b9b2e0b2SEd Tanous {boost::beast::http::verb::head, {{"Login"}}}, 1048b9b2e0b2SEd Tanous {boost::beast::http::verb::patch, {{"ConfigureUsers"}}}, 1049b9b2e0b2SEd Tanous {boost::beast::http::verb::put, {{"ConfigureUsers"}}}, 1050b9b2e0b2SEd Tanous {boost::beast::http::verb::delete_, {{"ConfigureUsers"}}}, 1051b9b2e0b2SEd Tanous {boost::beast::http::verb::post, {{"ConfigureUsers"}}}}; 1052b9b2e0b2SEd Tanous } 1053b9b2e0b2SEd Tanous 1054b9b2e0b2SEd Tanous private: 1055b9b2e0b2SEd Tanous void doGet(crow::Response& res, const crow::Request& req, 1056b9b2e0b2SEd Tanous const std::vector<std::string>& params) override 1057b9b2e0b2SEd Tanous { 10580f74e643SEd Tanous res.jsonValue = { 10590f74e643SEd Tanous {"@odata.context", 10600f74e643SEd Tanous "/redfish/v1/$metadata#ManagerAccount.ManagerAccount"}, 10610f74e643SEd Tanous {"@odata.type", "#ManagerAccount.v1_0_3.ManagerAccount"}, 10620f74e643SEd Tanous {"Name", "User Account"}, 10630f74e643SEd Tanous {"Description", "User Account"}, 10640f74e643SEd Tanous {"Password", nullptr}, 106584e12cb7SAppaRao Puli {"RoleId", "Administrator"}}; 10660f74e643SEd Tanous 1067b9b2e0b2SEd Tanous auto asyncResp = std::make_shared<AsyncResp>(res); 1068b9b2e0b2SEd Tanous 1069b9b2e0b2SEd Tanous if (params.size() != 1) 1070b9b2e0b2SEd Tanous { 1071f12894f8SJason M. Bills messages::internalError(asyncResp->res); 1072b9b2e0b2SEd Tanous return; 1073b9b2e0b2SEd Tanous } 1074b9b2e0b2SEd Tanous 1075b9b2e0b2SEd Tanous crow::connections::systemBus->async_method_call( 1076b9b2e0b2SEd Tanous [asyncResp, accountName{std::string(params[0])}]( 1077b9b2e0b2SEd Tanous const boost::system::error_code ec, 1078b9b2e0b2SEd Tanous const ManagedObjectType& users) { 1079b9b2e0b2SEd Tanous if (ec) 1080b9b2e0b2SEd Tanous { 1081f12894f8SJason M. Bills messages::internalError(asyncResp->res); 1082b9b2e0b2SEd Tanous return; 1083b9b2e0b2SEd Tanous } 108484e12cb7SAppaRao Puli auto userIt = users.begin(); 1085b9b2e0b2SEd Tanous 108684e12cb7SAppaRao Puli for (; userIt != users.end(); userIt++) 1087b9b2e0b2SEd Tanous { 108884e12cb7SAppaRao Puli if (boost::ends_with(userIt->first.str, "/" + accountName)) 1089b9b2e0b2SEd Tanous { 109084e12cb7SAppaRao Puli break; 1091b9b2e0b2SEd Tanous } 1092b9b2e0b2SEd Tanous } 109384e12cb7SAppaRao Puli if (userIt == users.end()) 1094b9b2e0b2SEd Tanous { 109584e12cb7SAppaRao Puli messages::resourceNotFound(asyncResp->res, "ManagerAccount", 109684e12cb7SAppaRao Puli accountName); 109784e12cb7SAppaRao Puli return; 109884e12cb7SAppaRao Puli } 109984e12cb7SAppaRao Puli for (const auto& interface : userIt->second) 110065b0dc32SEd Tanous { 110165b0dc32SEd Tanous if (interface.first == 110265b0dc32SEd Tanous "xyz.openbmc_project.User.Attributes") 110365b0dc32SEd Tanous { 110465b0dc32SEd Tanous for (const auto& property : interface.second) 110565b0dc32SEd Tanous { 110665b0dc32SEd Tanous if (property.first == "UserEnabled") 110765b0dc32SEd Tanous { 110865b0dc32SEd Tanous const bool* userEnabled = 1109abf2add6SEd Tanous std::get_if<bool>(&property.second); 111065b0dc32SEd Tanous if (userEnabled == nullptr) 111165b0dc32SEd Tanous { 111265b0dc32SEd Tanous BMCWEB_LOG_ERROR 111365b0dc32SEd Tanous << "UserEnabled wasn't a bool"; 111484e12cb7SAppaRao Puli messages::internalError(asyncResp->res); 111584e12cb7SAppaRao Puli return; 111665b0dc32SEd Tanous } 111765b0dc32SEd Tanous asyncResp->res.jsonValue["Enabled"] = 111865b0dc32SEd Tanous *userEnabled; 111965b0dc32SEd Tanous } 112065b0dc32SEd Tanous else if (property.first == 112165b0dc32SEd Tanous "UserLockedForFailedAttempt") 112265b0dc32SEd Tanous { 112365b0dc32SEd Tanous const bool* userLocked = 1124abf2add6SEd Tanous std::get_if<bool>(&property.second); 112565b0dc32SEd Tanous if (userLocked == nullptr) 112665b0dc32SEd Tanous { 112784e12cb7SAppaRao Puli BMCWEB_LOG_ERROR << "UserLockedForF" 112884e12cb7SAppaRao Puli "ailedAttempt " 112984e12cb7SAppaRao Puli "wasn't a bool"; 113084e12cb7SAppaRao Puli messages::internalError(asyncResp->res); 113184e12cb7SAppaRao Puli return; 113265b0dc32SEd Tanous } 113365b0dc32SEd Tanous asyncResp->res.jsonValue["Locked"] = 113465b0dc32SEd Tanous *userLocked; 113524c8542dSRatan Gupta asyncResp->res.jsonValue 113624c8542dSRatan Gupta ["Locked@Redfish.AllowableValues"] = { 11374d64ce34SGunnar Mills "false"}; 113865b0dc32SEd Tanous } 113984e12cb7SAppaRao Puli else if (property.first == "UserPrivilege") 114084e12cb7SAppaRao Puli { 114184e12cb7SAppaRao Puli const std::string* userRolePtr = 1142abf2add6SEd Tanous std::get_if<std::string>(&property.second); 114384e12cb7SAppaRao Puli if (userRolePtr == nullptr) 114484e12cb7SAppaRao Puli { 114584e12cb7SAppaRao Puli BMCWEB_LOG_ERROR 114684e12cb7SAppaRao Puli << "UserPrivilege wasn't a " 114784e12cb7SAppaRao Puli "string"; 114884e12cb7SAppaRao Puli messages::internalError(asyncResp->res); 114984e12cb7SAppaRao Puli return; 115084e12cb7SAppaRao Puli } 115184e12cb7SAppaRao Puli std::string priv = 115284e12cb7SAppaRao Puli getPrivilegeFromRoleId(*userRolePtr); 115384e12cb7SAppaRao Puli if (priv.empty()) 115484e12cb7SAppaRao Puli { 115584e12cb7SAppaRao Puli BMCWEB_LOG_ERROR << "Invalid user role"; 115684e12cb7SAppaRao Puli messages::internalError(asyncResp->res); 115784e12cb7SAppaRao Puli return; 115884e12cb7SAppaRao Puli } 115984e12cb7SAppaRao Puli asyncResp->res.jsonValue["RoleId"] = priv; 116084e12cb7SAppaRao Puli 116184e12cb7SAppaRao Puli asyncResp->res.jsonValue["Links"]["Role"] = { 116284e12cb7SAppaRao Puli {"@odata.id", "/redfish/v1/AccountService/" 116384e12cb7SAppaRao Puli "Roles/" + 116484e12cb7SAppaRao Puli priv}}; 116584e12cb7SAppaRao Puli } 116665b0dc32SEd Tanous } 116765b0dc32SEd Tanous } 116865b0dc32SEd Tanous } 116965b0dc32SEd Tanous 1170b9b2e0b2SEd Tanous asyncResp->res.jsonValue["@odata.id"] = 117184e12cb7SAppaRao Puli "/redfish/v1/AccountService/Accounts/" + accountName; 1172b9b2e0b2SEd Tanous asyncResp->res.jsonValue["Id"] = accountName; 1173b9b2e0b2SEd Tanous asyncResp->res.jsonValue["UserName"] = accountName; 1174b9b2e0b2SEd Tanous }, 1175b9b2e0b2SEd Tanous "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user", 1176b9b2e0b2SEd Tanous "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 1177b9b2e0b2SEd Tanous } 1178a840879dSEd Tanous 1179a840879dSEd Tanous void doPatch(crow::Response& res, const crow::Request& req, 1180a840879dSEd Tanous const std::vector<std::string>& params) override 1181a840879dSEd Tanous { 1182a840879dSEd Tanous auto asyncResp = std::make_shared<AsyncResp>(res); 1183a840879dSEd Tanous if (params.size() != 1) 1184a840879dSEd Tanous { 1185f12894f8SJason M. Bills messages::internalError(asyncResp->res); 1186a840879dSEd Tanous return; 1187a840879dSEd Tanous } 1188a840879dSEd Tanous 1189a24526dcSEd Tanous std::optional<std::string> newUserName; 1190a24526dcSEd Tanous std::optional<std::string> password; 1191a24526dcSEd Tanous std::optional<bool> enabled; 1192a24526dcSEd Tanous std::optional<std::string> roleId; 119324c8542dSRatan Gupta std::optional<bool> locked; 119484e12cb7SAppaRao Puli if (!json_util::readJson(req, res, "UserName", newUserName, "Password", 119524c8542dSRatan Gupta password, "RoleId", roleId, "Enabled", enabled, 119624c8542dSRatan Gupta "Locked", locked)) 1197a840879dSEd Tanous { 1198a840879dSEd Tanous return; 1199a840879dSEd Tanous } 1200a840879dSEd Tanous 120184e12cb7SAppaRao Puli const std::string& username = params[0]; 120284e12cb7SAppaRao Puli 120384e12cb7SAppaRao Puli if (!newUserName) 1204a840879dSEd Tanous { 120584e12cb7SAppaRao Puli // If the username isn't being updated, we can update the properties 120684e12cb7SAppaRao Puli // directly 120724c8542dSRatan Gupta updateUserProperties(asyncResp, username, password, enabled, roleId, 120824c8542dSRatan Gupta locked); 120984e12cb7SAppaRao Puli return; 121084e12cb7SAppaRao Puli } 121184e12cb7SAppaRao Puli else 121284e12cb7SAppaRao Puli { 121384e12cb7SAppaRao Puli crow::connections::systemBus->async_method_call( 121484e12cb7SAppaRao Puli [this, asyncResp, username, password(std::move(password)), 121584e12cb7SAppaRao Puli roleId(std::move(roleId)), enabled(std::move(enabled)), 121624c8542dSRatan Gupta newUser{std::string(*newUserName)}, locked(std::move(locked))]( 121784e12cb7SAppaRao Puli const boost::system::error_code ec) { 121884e12cb7SAppaRao Puli if (ec) 121984e12cb7SAppaRao Puli { 122084e12cb7SAppaRao Puli BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec; 1221a840879dSEd Tanous messages::resourceNotFound( 122284e12cb7SAppaRao Puli asyncResp->res, 122384e12cb7SAppaRao Puli "#ManagerAccount.v1_0_3.ManagerAccount", username); 1224a840879dSEd Tanous return; 1225a840879dSEd Tanous } 1226a840879dSEd Tanous 122784e12cb7SAppaRao Puli updateUserProperties(asyncResp, newUser, password, enabled, 122824c8542dSRatan Gupta roleId, locked); 122984e12cb7SAppaRao Puli }, 123084e12cb7SAppaRao Puli "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user", 123184e12cb7SAppaRao Puli "xyz.openbmc_project.User.Manager", "RenameUser", username, 123284e12cb7SAppaRao Puli *newUserName); 123384e12cb7SAppaRao Puli } 123484e12cb7SAppaRao Puli } 123584e12cb7SAppaRao Puli 123684e12cb7SAppaRao Puli void updateUserProperties(std::shared_ptr<AsyncResp> asyncResp, 123784e12cb7SAppaRao Puli const std::string& username, 1238a24526dcSEd Tanous std::optional<std::string> password, 1239a24526dcSEd Tanous std::optional<bool> enabled, 124024c8542dSRatan Gupta std::optional<std::string> roleId, 124124c8542dSRatan Gupta std::optional<bool> locked) 124284e12cb7SAppaRao Puli { 12439712f8acSEd Tanous if (password) 1244a840879dSEd Tanous { 12459712f8acSEd Tanous if (!pamUpdatePassword(username, *password)) 1246a840879dSEd Tanous { 1247a840879dSEd Tanous BMCWEB_LOG_ERROR << "pamUpdatePassword Failed"; 1248f12894f8SJason M. Bills messages::internalError(asyncResp->res); 1249a840879dSEd Tanous return; 1250a840879dSEd Tanous } 1251a840879dSEd Tanous } 1252a840879dSEd Tanous 125324c8542dSRatan Gupta std::string dbusObjectPath = "/xyz/openbmc_project/user/" + username; 125424c8542dSRatan Gupta dbus::utility::escapePathForDbus(dbusObjectPath); 125524c8542dSRatan Gupta 125624c8542dSRatan Gupta checkDbusPathExists( 125724c8542dSRatan Gupta dbusObjectPath, 125824c8542dSRatan Gupta [dbusObjectPath(std::move(dbusObjectPath)), username, 125924c8542dSRatan Gupta password(std::move(password)), roleId(std::move(roleId)), 126024c8542dSRatan Gupta enabled(std::move(enabled)), locked(std::move(locked)), 126124c8542dSRatan Gupta asyncResp{std::move(asyncResp)}](int rc) { 126224c8542dSRatan Gupta if (!rc) 126324c8542dSRatan Gupta { 126424c8542dSRatan Gupta messages::invalidObject(asyncResp->res, username.c_str()); 126524c8542dSRatan Gupta return; 126624c8542dSRatan Gupta } 12679712f8acSEd Tanous if (enabled) 1268a840879dSEd Tanous { 1269a840879dSEd Tanous crow::connections::systemBus->async_method_call( 1270a840879dSEd Tanous [asyncResp](const boost::system::error_code ec) { 1271a840879dSEd Tanous if (ec) 1272a840879dSEd Tanous { 127324c8542dSRatan Gupta BMCWEB_LOG_ERROR << "D-Bus responses error: " 127424c8542dSRatan Gupta << ec; 1275f12894f8SJason M. Bills messages::internalError(asyncResp->res); 1276a840879dSEd Tanous return; 1277a840879dSEd Tanous } 127884e12cb7SAppaRao Puli messages::success(asyncResp->res); 127984e12cb7SAppaRao Puli return; 128084e12cb7SAppaRao Puli }, 128184e12cb7SAppaRao Puli "xyz.openbmc_project.User.Manager", 128224c8542dSRatan Gupta dbusObjectPath.c_str(), 128384e12cb7SAppaRao Puli "org.freedesktop.DBus.Properties", "Set", 128484e12cb7SAppaRao Puli "xyz.openbmc_project.User.Attributes", "UserEnabled", 1285abf2add6SEd Tanous std::variant<bool>{*enabled}); 128684e12cb7SAppaRao Puli } 128784e12cb7SAppaRao Puli 128884e12cb7SAppaRao Puli if (roleId) 128984e12cb7SAppaRao Puli { 129084e12cb7SAppaRao Puli std::string priv = getRoleIdFromPrivilege(*roleId); 129184e12cb7SAppaRao Puli if (priv.empty()) 129284e12cb7SAppaRao Puli { 129324c8542dSRatan Gupta messages::propertyValueNotInList(asyncResp->res, 129424c8542dSRatan Gupta *roleId, "RoleId"); 129584e12cb7SAppaRao Puli return; 129684e12cb7SAppaRao Puli } 129784e12cb7SAppaRao Puli 129884e12cb7SAppaRao Puli crow::connections::systemBus->async_method_call( 129984e12cb7SAppaRao Puli [asyncResp](const boost::system::error_code ec) { 130084e12cb7SAppaRao Puli if (ec) 130184e12cb7SAppaRao Puli { 130224c8542dSRatan Gupta BMCWEB_LOG_ERROR << "D-Bus responses error: " 130324c8542dSRatan Gupta << ec; 130484e12cb7SAppaRao Puli messages::internalError(asyncResp->res); 130584e12cb7SAppaRao Puli return; 130684e12cb7SAppaRao Puli } 1307f12894f8SJason M. Bills messages::success(asyncResp->res); 1308a840879dSEd Tanous }, 1309a840879dSEd Tanous "xyz.openbmc_project.User.Manager", 131024c8542dSRatan Gupta dbusObjectPath.c_str(), 1311a840879dSEd Tanous "org.freedesktop.DBus.Properties", "Set", 131284e12cb7SAppaRao Puli "xyz.openbmc_project.User.Attributes", "UserPrivilege", 1313abf2add6SEd Tanous std::variant<std::string>{priv}); 1314a840879dSEd Tanous } 131524c8542dSRatan Gupta 131624c8542dSRatan Gupta if (locked) 131724c8542dSRatan Gupta { 131824c8542dSRatan Gupta // admin can unlock the account which is locked by 131924c8542dSRatan Gupta // successive authentication failures but admin should not 132024c8542dSRatan Gupta // be allowed to lock an account. 132124c8542dSRatan Gupta if (*locked) 132224c8542dSRatan Gupta { 132324c8542dSRatan Gupta messages::propertyValueNotInList(asyncResp->res, "true", 132424c8542dSRatan Gupta "Locked"); 132524c8542dSRatan Gupta return; 132624c8542dSRatan Gupta } 132724c8542dSRatan Gupta 132824c8542dSRatan Gupta crow::connections::systemBus->async_method_call( 132924c8542dSRatan Gupta [asyncResp](const boost::system::error_code ec) { 133024c8542dSRatan Gupta if (ec) 133124c8542dSRatan Gupta { 133224c8542dSRatan Gupta BMCWEB_LOG_ERROR << "D-Bus responses error: " 133324c8542dSRatan Gupta << ec; 133424c8542dSRatan Gupta messages::internalError(asyncResp->res); 133524c8542dSRatan Gupta return; 133624c8542dSRatan Gupta } 133724c8542dSRatan Gupta messages::success(asyncResp->res); 133824c8542dSRatan Gupta return; 133924c8542dSRatan Gupta }, 134024c8542dSRatan Gupta "xyz.openbmc_project.User.Manager", 134124c8542dSRatan Gupta dbusObjectPath.c_str(), 134224c8542dSRatan Gupta "org.freedesktop.DBus.Properties", "Set", 134324c8542dSRatan Gupta "xyz.openbmc_project.User.Attributes", 134424c8542dSRatan Gupta "UserLockedForFailedAttempt", 134524c8542dSRatan Gupta sdbusplus::message::variant<bool>{*locked}); 134624c8542dSRatan Gupta } 134724c8542dSRatan Gupta }); 1348a840879dSEd Tanous } 134906e086d9SEd Tanous 135006e086d9SEd Tanous void doDelete(crow::Response& res, const crow::Request& req, 135106e086d9SEd Tanous const std::vector<std::string>& params) override 135206e086d9SEd Tanous { 135306e086d9SEd Tanous auto asyncResp = std::make_shared<AsyncResp>(res); 135406e086d9SEd Tanous 135506e086d9SEd Tanous if (params.size() != 1) 135606e086d9SEd Tanous { 1357f12894f8SJason M. Bills messages::internalError(asyncResp->res); 135806e086d9SEd Tanous return; 135906e086d9SEd Tanous } 136006e086d9SEd Tanous 136106e086d9SEd Tanous const std::string userPath = "/xyz/openbmc_project/user/" + params[0]; 136206e086d9SEd Tanous 136306e086d9SEd Tanous crow::connections::systemBus->async_method_call( 136406e086d9SEd Tanous [asyncResp, username{std::move(params[0])}]( 136506e086d9SEd Tanous const boost::system::error_code ec) { 136606e086d9SEd Tanous if (ec) 136706e086d9SEd Tanous { 136806e086d9SEd Tanous messages::resourceNotFound( 1369f12894f8SJason M. Bills asyncResp->res, "#ManagerAccount.v1_0_3.ManagerAccount", 1370f12894f8SJason M. Bills username); 137106e086d9SEd Tanous return; 137206e086d9SEd Tanous } 137306e086d9SEd Tanous 1374f12894f8SJason M. Bills messages::accountRemoved(asyncResp->res); 137506e086d9SEd Tanous }, 137606e086d9SEd Tanous "xyz.openbmc_project.User.Manager", userPath, 137706e086d9SEd Tanous "xyz.openbmc_project.Object.Delete", "Delete"); 137806e086d9SEd Tanous } 137984e12cb7SAppaRao Puli }; 138088d16c9aSLewanczyk, Dawid 138188d16c9aSLewanczyk, Dawid } // namespace redfish 1382