188d16c9aSLewanczyk, Dawid /* 288d16c9aSLewanczyk, Dawid // Copyright (c) 2018 Intel Corporation 388d16c9aSLewanczyk, Dawid // 488d16c9aSLewanczyk, Dawid // Licensed under the Apache License, Version 2.0 (the "License"); 588d16c9aSLewanczyk, Dawid // you may not use this file except in compliance with the License. 688d16c9aSLewanczyk, Dawid // You may obtain a copy of the License at 788d16c9aSLewanczyk, Dawid // 888d16c9aSLewanczyk, Dawid // http://www.apache.org/licenses/LICENSE-2.0 988d16c9aSLewanczyk, Dawid // 1088d16c9aSLewanczyk, Dawid // Unless required by applicable law or agreed to in writing, software 1188d16c9aSLewanczyk, Dawid // distributed under the License is distributed on an "AS IS" BASIS, 1288d16c9aSLewanczyk, Dawid // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1388d16c9aSLewanczyk, Dawid // See the License for the specific language governing permissions and 1488d16c9aSLewanczyk, Dawid // limitations under the License. 1588d16c9aSLewanczyk, Dawid */ 1688d16c9aSLewanczyk, Dawid #pragma once 1788d16c9aSLewanczyk, Dawid #include "node.hpp" 1888d16c9aSLewanczyk, Dawid 1924c8542dSRatan Gupta #include <dbus_utility.hpp> 2065b0dc32SEd Tanous #include <error_messages.hpp> 21b9b2e0b2SEd Tanous #include <openbmc_dbus_rest.hpp> 22a840879dSEd Tanous #include <utils/json_utils.hpp> 23abf2add6SEd Tanous #include <variant> 24b9b2e0b2SEd Tanous 251abe55efSEd Tanous namespace redfish 261abe55efSEd Tanous { 2788d16c9aSLewanczyk, Dawid 286973a582SRatan Gupta constexpr const char* ldapConfigObject = 296973a582SRatan Gupta "/xyz/openbmc_project/user/ldap/openldap"; 30ab828d7cSRatan Gupta constexpr const char* ADConfigObject = 31ab828d7cSRatan Gupta "/xyz/openbmc_project/user/ldap/active_directory"; 32ab828d7cSRatan Gupta 336973a582SRatan Gupta constexpr const char* ldapRootObject = "/xyz/openbmc_project/user/ldap"; 346973a582SRatan Gupta constexpr const char* ldapDbusService = "xyz.openbmc_project.Ldap.Config"; 356973a582SRatan Gupta constexpr const char* ldapConfigInterface = 366973a582SRatan Gupta "xyz.openbmc_project.User.Ldap.Config"; 376973a582SRatan Gupta constexpr const char* ldapCreateInterface = 386973a582SRatan Gupta "xyz.openbmc_project.User.Ldap.Create"; 396973a582SRatan Gupta constexpr const char* ldapEnableInterface = "xyz.openbmc_project.Object.Enable"; 406973a582SRatan Gupta constexpr const char* dbusObjManagerIntf = "org.freedesktop.DBus.ObjectManager"; 416973a582SRatan Gupta constexpr const char* propertyInterface = "org.freedesktop.DBus.Properties"; 426973a582SRatan Gupta constexpr const char* mapperBusName = "xyz.openbmc_project.ObjectMapper"; 436973a582SRatan Gupta constexpr const char* mapperObjectPath = "/xyz/openbmc_project/object_mapper"; 446973a582SRatan Gupta constexpr const char* mapperIntf = "xyz.openbmc_project.ObjectMapper"; 456973a582SRatan Gupta 46*54fc587aSNagaraju Goruganti struct LDAPRoleMapData 47*54fc587aSNagaraju Goruganti { 48*54fc587aSNagaraju Goruganti std::string groupName; 49*54fc587aSNagaraju Goruganti std::string privilege; 50*54fc587aSNagaraju Goruganti }; 51*54fc587aSNagaraju Goruganti 526973a582SRatan Gupta struct LDAPConfigData 536973a582SRatan Gupta { 546973a582SRatan Gupta std::string uri{}; 556973a582SRatan Gupta std::string bindDN{}; 566973a582SRatan Gupta std::string baseDN{}; 576973a582SRatan Gupta std::string searchScope{}; 586973a582SRatan Gupta std::string serverType{}; 596973a582SRatan Gupta bool serviceEnabled = false; 606973a582SRatan Gupta std::string userNameAttribute{}; 616973a582SRatan Gupta std::string groupAttribute{}; 62*54fc587aSNagaraju Goruganti std::vector<std::pair<std::string, LDAPRoleMapData>> groupRoleList; 636973a582SRatan Gupta }; 646973a582SRatan Gupta 65b9b2e0b2SEd Tanous using ManagedObjectType = std::vector<std::pair< 66b9b2e0b2SEd Tanous sdbusplus::message::object_path, 67b9b2e0b2SEd Tanous boost::container::flat_map< 68abf2add6SEd Tanous std::string, boost::container::flat_map< 69abf2add6SEd Tanous std::string, std::variant<bool, std::string>>>>>; 706973a582SRatan Gupta using GetObjectType = 716973a582SRatan Gupta std::vector<std::pair<std::string, std::vector<std::string>>>; 7284e12cb7SAppaRao Puli 73*54fc587aSNagaraju Goruganti inline std::string getRoleIdFromPrivilege(std::string_view role) 7484e12cb7SAppaRao Puli { 7584e12cb7SAppaRao Puli if (role == "priv-admin") 7684e12cb7SAppaRao Puli { 7784e12cb7SAppaRao Puli return "Administrator"; 7884e12cb7SAppaRao Puli } 7984e12cb7SAppaRao Puli else if (role == "priv-callback") 8084e12cb7SAppaRao Puli { 8184e12cb7SAppaRao Puli return "Callback"; 8284e12cb7SAppaRao Puli } 8384e12cb7SAppaRao Puli else if (role == "priv-user") 8484e12cb7SAppaRao Puli { 8584e12cb7SAppaRao Puli return "User"; 8684e12cb7SAppaRao Puli } 8784e12cb7SAppaRao Puli else if (role == "priv-operator") 8884e12cb7SAppaRao Puli { 8984e12cb7SAppaRao Puli return "Operator"; 9084e12cb7SAppaRao Puli } 9184e12cb7SAppaRao Puli return ""; 9284e12cb7SAppaRao Puli } 93*54fc587aSNagaraju Goruganti inline std::string getPrivilegeFromRoleId(std::string_view role) 9484e12cb7SAppaRao Puli { 9584e12cb7SAppaRao Puli if (role == "Administrator") 9684e12cb7SAppaRao Puli { 9784e12cb7SAppaRao Puli return "priv-admin"; 9884e12cb7SAppaRao Puli } 9984e12cb7SAppaRao Puli else if (role == "Callback") 10084e12cb7SAppaRao Puli { 10184e12cb7SAppaRao Puli return "priv-callback"; 10284e12cb7SAppaRao Puli } 10384e12cb7SAppaRao Puli else if (role == "User") 10484e12cb7SAppaRao Puli { 10584e12cb7SAppaRao Puli return "priv-user"; 10684e12cb7SAppaRao Puli } 10784e12cb7SAppaRao Puli else if (role == "Operator") 10884e12cb7SAppaRao Puli { 10984e12cb7SAppaRao Puli return "priv-operator"; 11084e12cb7SAppaRao Puli } 11184e12cb7SAppaRao Puli return ""; 11284e12cb7SAppaRao Puli } 113b9b2e0b2SEd Tanous 1146973a582SRatan Gupta void parseLDAPConfigData(nlohmann::json& json_response, 115ab828d7cSRatan Gupta const LDAPConfigData& confData, 116ab828d7cSRatan Gupta const std::string& ldapType) 1176973a582SRatan Gupta { 118ab828d7cSRatan Gupta std::string service = 119ab828d7cSRatan Gupta (ldapType == "LDAP") ? "LDAPService" : "ActiveDirectoryService"; 12037cce918SMarri Devender Rao nlohmann::json ldap = { 1216973a582SRatan Gupta {"AccountProviderType", service}, 1226973a582SRatan Gupta {"ServiceEnabled", confData.serviceEnabled}, 1236973a582SRatan Gupta {"ServiceAddresses", nlohmann::json::array({confData.uri})}, 1246973a582SRatan Gupta {"Authentication", 1256973a582SRatan Gupta {{"AuthenticationType", "UsernameAndPassword"}, 1266973a582SRatan Gupta {"Username", confData.bindDN}, 1276973a582SRatan Gupta {"Password", nullptr}}}, 1286973a582SRatan Gupta {"LDAPService", 1296973a582SRatan Gupta {{"SearchSettings", 1306973a582SRatan Gupta {{"BaseDistinguishedNames", 1316973a582SRatan Gupta nlohmann::json::array({confData.baseDN})}, 1326973a582SRatan Gupta {"UsernameAttribute", confData.userNameAttribute}, 1336973a582SRatan Gupta {"GroupsAttribute", confData.groupAttribute}}}}}, 1346973a582SRatan Gupta }; 135*54fc587aSNagaraju Goruganti 13637cce918SMarri Devender Rao json_response[ldapType].update(std::move(ldap)); 137*54fc587aSNagaraju Goruganti 138*54fc587aSNagaraju Goruganti nlohmann::json& roleMapArray = json_response[ldapType]["RemoteRoleMapping"]; 139*54fc587aSNagaraju Goruganti roleMapArray = nlohmann::json::array(); 140*54fc587aSNagaraju Goruganti for (auto& obj : confData.groupRoleList) 141*54fc587aSNagaraju Goruganti { 142*54fc587aSNagaraju Goruganti BMCWEB_LOG_DEBUG << "Pushing the data groupName=" 143*54fc587aSNagaraju Goruganti << obj.second.groupName << "\n"; 144*54fc587aSNagaraju Goruganti roleMapArray.push_back( 145*54fc587aSNagaraju Goruganti {nlohmann::json::array({"RemoteGroup", obj.second.groupName}), 146*54fc587aSNagaraju Goruganti nlohmann::json::array( 147*54fc587aSNagaraju Goruganti {"LocalRole", getRoleIdFromPrivilege(obj.second.privilege)})}); 148*54fc587aSNagaraju Goruganti } 1496973a582SRatan Gupta } 1506973a582SRatan Gupta 1516973a582SRatan Gupta /** 1526973a582SRatan Gupta * Function that retrieves all properties for LDAP config object 1536973a582SRatan Gupta * into JSON 1546973a582SRatan Gupta */ 1556973a582SRatan Gupta template <typename CallbackFunc> 1566973a582SRatan Gupta inline void getLDAPConfigData(const std::string& ldapType, 1576973a582SRatan Gupta CallbackFunc&& callback) 1586973a582SRatan Gupta { 159*54fc587aSNagaraju Goruganti 160*54fc587aSNagaraju Goruganti const std::array<const char*, 2> interfaces = {ldapEnableInterface, 161*54fc587aSNagaraju Goruganti ldapConfigInterface}; 162*54fc587aSNagaraju Goruganti 163*54fc587aSNagaraju Goruganti crow::connections::systemBus->async_method_call( 164*54fc587aSNagaraju Goruganti [callback, ldapType](const boost::system::error_code ec, 165*54fc587aSNagaraju Goruganti const GetObjectType& resp) { 166*54fc587aSNagaraju Goruganti LDAPConfigData confData{}; 167*54fc587aSNagaraju Goruganti if (ec || resp.empty()) 168*54fc587aSNagaraju Goruganti { 169*54fc587aSNagaraju Goruganti BMCWEB_LOG_ERROR << "DBUS response error during getting of " 170*54fc587aSNagaraju Goruganti "service name: " 171*54fc587aSNagaraju Goruganti << ec; 172*54fc587aSNagaraju Goruganti callback(false, confData, ldapType); 173*54fc587aSNagaraju Goruganti return; 174*54fc587aSNagaraju Goruganti } 175*54fc587aSNagaraju Goruganti std::string service = resp.begin()->first; 176*54fc587aSNagaraju Goruganti crow::connections::systemBus->async_method_call( 177*54fc587aSNagaraju Goruganti [callback, ldapType](const boost::system::error_code error_code, 1786973a582SRatan Gupta const ManagedObjectType& ldapObjects) { 1796973a582SRatan Gupta LDAPConfigData confData{}; 1806973a582SRatan Gupta if (error_code) 1816973a582SRatan Gupta { 182ab828d7cSRatan Gupta callback(false, confData, ldapType); 183*54fc587aSNagaraju Goruganti BMCWEB_LOG_ERROR << "D-Bus responses error: " 184*54fc587aSNagaraju Goruganti << error_code; 1856973a582SRatan Gupta return; 1866973a582SRatan Gupta } 187ab828d7cSRatan Gupta 188ab828d7cSRatan Gupta std::string ldapDbusType; 189*54fc587aSNagaraju Goruganti std::string searchString; 190*54fc587aSNagaraju Goruganti 191ab828d7cSRatan Gupta if (ldapType == "LDAP") 192ab828d7cSRatan Gupta { 193*54fc587aSNagaraju Goruganti ldapDbusType = "xyz.openbmc_project.User.Ldap.Config." 194*54fc587aSNagaraju Goruganti "Type.OpenLdap"; 195*54fc587aSNagaraju Goruganti searchString = "openldap"; 196ab828d7cSRatan Gupta } 197ab828d7cSRatan Gupta else if (ldapType == "ActiveDirectory") 198ab828d7cSRatan Gupta { 199*54fc587aSNagaraju Goruganti ldapDbusType = 200*54fc587aSNagaraju Goruganti "xyz.openbmc_project.User.Ldap.Config.Type." 201ab828d7cSRatan Gupta "ActiveDirectory"; 202*54fc587aSNagaraju Goruganti searchString = "active_directory"; 203ab828d7cSRatan Gupta } 204ab828d7cSRatan Gupta else 205ab828d7cSRatan Gupta { 206*54fc587aSNagaraju Goruganti BMCWEB_LOG_ERROR 207*54fc587aSNagaraju Goruganti << "Can't get the DbusType for the given type=" 208ab828d7cSRatan Gupta << ldapType; 209ab828d7cSRatan Gupta callback(false, confData, ldapType); 210ab828d7cSRatan Gupta return; 211ab828d7cSRatan Gupta } 212ab828d7cSRatan Gupta 213ab828d7cSRatan Gupta std::string ldapEnableInterfaceStr = ldapEnableInterface; 214ab828d7cSRatan Gupta std::string ldapConfigInterfaceStr = ldapConfigInterface; 215ab828d7cSRatan Gupta 2166973a582SRatan Gupta for (const auto& object : ldapObjects) 2176973a582SRatan Gupta { 218*54fc587aSNagaraju Goruganti // let's find the object whose ldap type is equal to the 219*54fc587aSNagaraju Goruganti // given type 220*54fc587aSNagaraju Goruganti if (object.first.str.find(searchString) == 221*54fc587aSNagaraju Goruganti std::string::npos) 2226973a582SRatan Gupta { 223ab828d7cSRatan Gupta continue; 224ab828d7cSRatan Gupta } 225ab828d7cSRatan Gupta 2266973a582SRatan Gupta for (const auto& interface : object.second) 2276973a582SRatan Gupta { 2286973a582SRatan Gupta if (interface.first == ldapEnableInterfaceStr) 2296973a582SRatan Gupta { 2306973a582SRatan Gupta // rest of the properties are string. 2316973a582SRatan Gupta for (const auto& property : interface.second) 2326973a582SRatan Gupta { 2336973a582SRatan Gupta if (property.first == "Enabled") 2346973a582SRatan Gupta { 2356973a582SRatan Gupta const bool* value = 2366973a582SRatan Gupta std::get_if<bool>(&property.second); 2376973a582SRatan Gupta if (value == nullptr) 2386973a582SRatan Gupta { 2396973a582SRatan Gupta continue; 2406973a582SRatan Gupta } 2416973a582SRatan Gupta confData.serviceEnabled = *value; 2426973a582SRatan Gupta break; 2436973a582SRatan Gupta } 2446973a582SRatan Gupta } 2456973a582SRatan Gupta } 2466973a582SRatan Gupta else if (interface.first == ldapConfigInterfaceStr) 2476973a582SRatan Gupta { 2486973a582SRatan Gupta 2496973a582SRatan Gupta for (const auto& property : interface.second) 2506973a582SRatan Gupta { 2516973a582SRatan Gupta const std::string* value = 252*54fc587aSNagaraju Goruganti std::get_if<std::string>( 253*54fc587aSNagaraju Goruganti &property.second); 2546973a582SRatan Gupta if (value == nullptr) 2556973a582SRatan Gupta { 2566973a582SRatan Gupta continue; 2576973a582SRatan Gupta } 2586973a582SRatan Gupta if (property.first == "LDAPServerURI") 2596973a582SRatan Gupta { 2606973a582SRatan Gupta confData.uri = *value; 2616973a582SRatan Gupta } 2626973a582SRatan Gupta else if (property.first == "LDAPBindDN") 2636973a582SRatan Gupta { 2646973a582SRatan Gupta confData.bindDN = *value; 2656973a582SRatan Gupta } 2666973a582SRatan Gupta else if (property.first == "LDAPBaseDN") 2676973a582SRatan Gupta { 2686973a582SRatan Gupta confData.baseDN = *value; 2696973a582SRatan Gupta } 270*54fc587aSNagaraju Goruganti else if (property.first == 271*54fc587aSNagaraju Goruganti "LDAPSearchScope") 2726973a582SRatan Gupta { 2736973a582SRatan Gupta confData.searchScope = *value; 2746973a582SRatan Gupta } 275*54fc587aSNagaraju Goruganti else if (property.first == 276*54fc587aSNagaraju Goruganti "GroupNameAttribute") 2776973a582SRatan Gupta { 2786973a582SRatan Gupta confData.groupAttribute = *value; 2796973a582SRatan Gupta } 280*54fc587aSNagaraju Goruganti else if (property.first == 281*54fc587aSNagaraju Goruganti "UserNameAttribute") 2826973a582SRatan Gupta { 2836973a582SRatan Gupta confData.userNameAttribute = *value; 2846973a582SRatan Gupta } 285*54fc587aSNagaraju Goruganti else if (property.first == "LDAPType") 286ab828d7cSRatan Gupta { 287*54fc587aSNagaraju Goruganti confData.serverType = *value; 288*54fc587aSNagaraju Goruganti } 289*54fc587aSNagaraju Goruganti } 290*54fc587aSNagaraju Goruganti } 291*54fc587aSNagaraju Goruganti else if (interface.first == 292*54fc587aSNagaraju Goruganti "xyz.openbmc_project.User." 293*54fc587aSNagaraju Goruganti "PrivilegeMapperEntry") 294*54fc587aSNagaraju Goruganti { 295*54fc587aSNagaraju Goruganti LDAPRoleMapData roleMapData{}; 296*54fc587aSNagaraju Goruganti for (const auto& property : interface.second) 297*54fc587aSNagaraju Goruganti { 298*54fc587aSNagaraju Goruganti const std::string* value = 299*54fc587aSNagaraju Goruganti std::get_if<std::string>( 300*54fc587aSNagaraju Goruganti &property.second); 301*54fc587aSNagaraju Goruganti 302*54fc587aSNagaraju Goruganti if (value == nullptr) 303*54fc587aSNagaraju Goruganti { 304*54fc587aSNagaraju Goruganti continue; 305*54fc587aSNagaraju Goruganti } 306*54fc587aSNagaraju Goruganti 307*54fc587aSNagaraju Goruganti if (property.first == "GroupName") 308*54fc587aSNagaraju Goruganti { 309*54fc587aSNagaraju Goruganti roleMapData.groupName = *value; 310*54fc587aSNagaraju Goruganti } 311*54fc587aSNagaraju Goruganti else if (property.first == "Privilege") 312*54fc587aSNagaraju Goruganti { 313*54fc587aSNagaraju Goruganti roleMapData.privilege = *value; 314*54fc587aSNagaraju Goruganti } 315*54fc587aSNagaraju Goruganti } 316*54fc587aSNagaraju Goruganti 317*54fc587aSNagaraju Goruganti confData.groupRoleList.push_back(std::make_pair( 318*54fc587aSNagaraju Goruganti object.first.str, roleMapData)); 319*54fc587aSNagaraju Goruganti } 320*54fc587aSNagaraju Goruganti } 321*54fc587aSNagaraju Goruganti } 322ab828d7cSRatan Gupta callback(true, confData, ldapType); 323*54fc587aSNagaraju Goruganti }, 324*54fc587aSNagaraju Goruganti service, ldapRootObject, dbusObjManagerIntf, 3256973a582SRatan Gupta "GetManagedObjects"); 326*54fc587aSNagaraju Goruganti }, 327*54fc587aSNagaraju Goruganti mapperBusName, mapperObjectPath, mapperIntf, "GetObject", 328*54fc587aSNagaraju Goruganti ldapConfigObject, interfaces); 3296973a582SRatan Gupta } 3306973a582SRatan Gupta 3311abe55efSEd Tanous class AccountService : public Node 3321abe55efSEd Tanous { 33388d16c9aSLewanczyk, Dawid public: 3341abe55efSEd Tanous AccountService(CrowApp& app) : Node(app, "/redfish/v1/AccountService/") 3351abe55efSEd Tanous { 3363ebd75f7SEd Tanous entityPrivileges = { 3374b1b8683SBorawski.Lukasz {boost::beast::http::verb::get, 3384b1b8683SBorawski.Lukasz {{"ConfigureUsers"}, {"ConfigureManager"}}}, 339e0d918bcSEd Tanous {boost::beast::http::verb::head, {{"Login"}}}, 340e0d918bcSEd Tanous {boost::beast::http::verb::patch, {{"ConfigureUsers"}}}, 341e0d918bcSEd Tanous {boost::beast::http::verb::put, {{"ConfigureUsers"}}}, 342e0d918bcSEd Tanous {boost::beast::http::verb::delete_, {{"ConfigureUsers"}}}, 343e0d918bcSEd Tanous {boost::beast::http::verb::post, {{"ConfigureUsers"}}}}; 34488d16c9aSLewanczyk, Dawid } 34588d16c9aSLewanczyk, Dawid 34688d16c9aSLewanczyk, Dawid private: 3478a07d286SRatan Gupta /** 3488a07d286SRatan Gupta * @brief parses the authentication section under the LDAP 3498a07d286SRatan Gupta * @param input JSON data 3508a07d286SRatan Gupta * @param asyncResp pointer to the JSON response 3518a07d286SRatan Gupta * @param userName userName to be filled from the given JSON. 3528a07d286SRatan Gupta * @param password password to be filled from the given JSON. 3538a07d286SRatan Gupta */ 3548a07d286SRatan Gupta void 3558a07d286SRatan Gupta parseLDAPAuthenticationJson(nlohmann::json input, 3568a07d286SRatan Gupta const std::shared_ptr<AsyncResp>& asyncResp, 3578a07d286SRatan Gupta std::optional<std::string>& username, 3588a07d286SRatan Gupta std::optional<std::string>& password) 3598a07d286SRatan Gupta { 3608a07d286SRatan Gupta std::optional<std::string> authType; 3618a07d286SRatan Gupta 3628a07d286SRatan Gupta if (!json_util::readJson(input, asyncResp->res, "AuthenticationType", 3638a07d286SRatan Gupta authType, "Username", username, "Password", 3648a07d286SRatan Gupta password)) 3658a07d286SRatan Gupta { 3668a07d286SRatan Gupta return; 3678a07d286SRatan Gupta } 3688a07d286SRatan Gupta if (!authType) 3698a07d286SRatan Gupta { 3708a07d286SRatan Gupta return; 3718a07d286SRatan Gupta } 3728a07d286SRatan Gupta if (*authType != "UsernameAndPassword") 3738a07d286SRatan Gupta { 3748a07d286SRatan Gupta messages::propertyValueNotInList(asyncResp->res, *authType, 3758a07d286SRatan Gupta "AuthenticationType"); 3768a07d286SRatan Gupta return; 3778a07d286SRatan Gupta } 3788a07d286SRatan Gupta } 3798a07d286SRatan Gupta /** 3808a07d286SRatan Gupta * @brief parses the LDAPService section under the LDAP 3818a07d286SRatan Gupta * @param input JSON data 3828a07d286SRatan Gupta * @param asyncResp pointer to the JSON response 3838a07d286SRatan Gupta * @param baseDNList baseDN to be filled from the given JSON. 3848a07d286SRatan Gupta * @param userNameAttribute userName to be filled from the given JSON. 3858a07d286SRatan Gupta * @param groupaAttribute password to be filled from the given JSON. 3868a07d286SRatan Gupta */ 3878a07d286SRatan Gupta 3888a07d286SRatan Gupta void parseLDAPServiceJson( 3898a07d286SRatan Gupta nlohmann::json input, const std::shared_ptr<AsyncResp>& asyncResp, 3908a07d286SRatan Gupta std::optional<std::vector<std::string>>& baseDNList, 3918a07d286SRatan Gupta std::optional<std::string>& userNameAttribute, 3928a07d286SRatan Gupta std::optional<std::string>& groupsAttribute) 3938a07d286SRatan Gupta { 3948a07d286SRatan Gupta std::optional<nlohmann::json> searchSettings; 3958a07d286SRatan Gupta 3968a07d286SRatan Gupta if (!json_util::readJson(input, asyncResp->res, "SearchSettings", 3978a07d286SRatan Gupta searchSettings)) 3988a07d286SRatan Gupta { 3998a07d286SRatan Gupta return; 4008a07d286SRatan Gupta } 4018a07d286SRatan Gupta if (!searchSettings) 4028a07d286SRatan Gupta { 4038a07d286SRatan Gupta return; 4048a07d286SRatan Gupta } 4058a07d286SRatan Gupta if (!json_util::readJson(*searchSettings, asyncResp->res, 4068a07d286SRatan Gupta "BaseDistinguishedNames", baseDNList, 4078a07d286SRatan Gupta "UsernameAttribute", userNameAttribute, 4088a07d286SRatan Gupta "GroupsAttribute", groupsAttribute)) 4098a07d286SRatan Gupta { 4108a07d286SRatan Gupta return; 4118a07d286SRatan Gupta } 4128a07d286SRatan Gupta } 4138a07d286SRatan Gupta /** 4148a07d286SRatan Gupta * @brief updates the LDAP server address and updates the 4158a07d286SRatan Gupta json response with the new value. 4168a07d286SRatan Gupta * @param serviceAddressList address to be updated. 4178a07d286SRatan Gupta * @param asyncResp pointer to the JSON response 4188a07d286SRatan Gupta * @param ldapServerElementName Type of LDAP 4198a07d286SRatan Gupta server(openLDAP/ActiveDirectory) 4208a07d286SRatan Gupta */ 4218a07d286SRatan Gupta 4228a07d286SRatan Gupta void handleServiceAddressPatch( 4238a07d286SRatan Gupta const std::vector<std::string>& serviceAddressList, 4248a07d286SRatan Gupta const std::shared_ptr<AsyncResp>& asyncResp, 4258a07d286SRatan Gupta const std::string& ldapServerElementName, 4268a07d286SRatan Gupta const std::string& ldapConfigObject) 4278a07d286SRatan Gupta { 4288a07d286SRatan Gupta crow::connections::systemBus->async_method_call( 4298a07d286SRatan Gupta [asyncResp, ldapServerElementName, 4308a07d286SRatan Gupta serviceAddressList](const boost::system::error_code ec) { 4318a07d286SRatan Gupta if (ec) 4328a07d286SRatan Gupta { 4338a07d286SRatan Gupta BMCWEB_LOG_DEBUG 4348a07d286SRatan Gupta << "Error Occured in updating the service address"; 4358a07d286SRatan Gupta messages::internalError(asyncResp->res); 4368a07d286SRatan Gupta return; 4378a07d286SRatan Gupta } 4388a07d286SRatan Gupta std::vector<std::string> modifiedserviceAddressList = { 4398a07d286SRatan Gupta serviceAddressList.front()}; 4408a07d286SRatan Gupta asyncResp->res 4418a07d286SRatan Gupta .jsonValue[ldapServerElementName]["ServiceAddresses"] = 4428a07d286SRatan Gupta modifiedserviceAddressList; 4438a07d286SRatan Gupta if ((serviceAddressList).size() > 1) 4448a07d286SRatan Gupta { 4458a07d286SRatan Gupta messages::propertyValueModified(asyncResp->res, 4468a07d286SRatan Gupta "ServiceAddresses", 4478a07d286SRatan Gupta serviceAddressList.front()); 4488a07d286SRatan Gupta } 4498a07d286SRatan Gupta BMCWEB_LOG_DEBUG << "Updated the service address"; 4508a07d286SRatan Gupta }, 4518a07d286SRatan Gupta ldapDbusService, ldapConfigObject, propertyInterface, "Set", 4528a07d286SRatan Gupta ldapConfigInterface, "LDAPServerURI", 4538a07d286SRatan Gupta std::variant<std::string>(serviceAddressList.front())); 4548a07d286SRatan Gupta } 4558a07d286SRatan Gupta /** 4568a07d286SRatan Gupta * @brief updates the LDAP Bind DN and updates the 4578a07d286SRatan Gupta json response with the new value. 4588a07d286SRatan Gupta * @param username name of the user which needs to be updated. 4598a07d286SRatan Gupta * @param asyncResp pointer to the JSON response 4608a07d286SRatan Gupta * @param ldapServerElementName Type of LDAP 4618a07d286SRatan Gupta server(openLDAP/ActiveDirectory) 4628a07d286SRatan Gupta */ 4638a07d286SRatan Gupta 4648a07d286SRatan Gupta void handleUserNamePatch(const std::string& username, 4658a07d286SRatan Gupta const std::shared_ptr<AsyncResp>& asyncResp, 4668a07d286SRatan Gupta const std::string& ldapServerElementName, 4678a07d286SRatan Gupta const std::string& ldapConfigObject) 4688a07d286SRatan Gupta { 4698a07d286SRatan Gupta crow::connections::systemBus->async_method_call( 4708a07d286SRatan Gupta [asyncResp, username, 4718a07d286SRatan Gupta ldapServerElementName](const boost::system::error_code ec) { 4728a07d286SRatan Gupta if (ec) 4738a07d286SRatan Gupta { 4748a07d286SRatan Gupta BMCWEB_LOG_DEBUG 4758a07d286SRatan Gupta << "Error occured in updating the username"; 4768a07d286SRatan Gupta messages::internalError(asyncResp->res); 4778a07d286SRatan Gupta return; 4788a07d286SRatan Gupta } 4798a07d286SRatan Gupta asyncResp->res.jsonValue[ldapServerElementName] 4808a07d286SRatan Gupta ["Authentication"]["Username"] = 4818a07d286SRatan Gupta username; 4828a07d286SRatan Gupta BMCWEB_LOG_DEBUG << "Updated the username"; 4838a07d286SRatan Gupta }, 4848a07d286SRatan Gupta ldapDbusService, ldapConfigObject, propertyInterface, "Set", 4858a07d286SRatan Gupta ldapConfigInterface, "LDAPBindDN", 4868a07d286SRatan Gupta std::variant<std::string>(username)); 4878a07d286SRatan Gupta } 4888a07d286SRatan Gupta 4898a07d286SRatan Gupta /** 4908a07d286SRatan Gupta * @brief updates the LDAP password 4918a07d286SRatan Gupta * @param password : ldap password which needs to be updated. 4928a07d286SRatan Gupta * @param asyncResp pointer to the JSON response 4938a07d286SRatan Gupta * @param ldapServerElementName Type of LDAP 4948a07d286SRatan Gupta * server(openLDAP/ActiveDirectory) 4958a07d286SRatan Gupta */ 4968a07d286SRatan Gupta 4978a07d286SRatan Gupta void handlePasswordPatch(const std::string& password, 4988a07d286SRatan Gupta const std::shared_ptr<AsyncResp>& asyncResp, 4998a07d286SRatan Gupta const std::string& ldapServerElementName, 5008a07d286SRatan Gupta const std::string& ldapConfigObject) 5018a07d286SRatan Gupta { 5028a07d286SRatan Gupta crow::connections::systemBus->async_method_call( 5038a07d286SRatan Gupta [asyncResp, password, 5048a07d286SRatan Gupta ldapServerElementName](const boost::system::error_code ec) { 5058a07d286SRatan Gupta if (ec) 5068a07d286SRatan Gupta { 5078a07d286SRatan Gupta BMCWEB_LOG_DEBUG 5088a07d286SRatan Gupta << "Error occured in updating the password"; 5098a07d286SRatan Gupta messages::internalError(asyncResp->res); 5108a07d286SRatan Gupta return; 5118a07d286SRatan Gupta } 5128a07d286SRatan Gupta asyncResp->res.jsonValue[ldapServerElementName] 5138a07d286SRatan Gupta ["Authentication"]["Password"] = ""; 5148a07d286SRatan Gupta BMCWEB_LOG_DEBUG << "Updated the password"; 5158a07d286SRatan Gupta }, 5168a07d286SRatan Gupta ldapDbusService, ldapConfigObject, propertyInterface, "Set", 5178a07d286SRatan Gupta ldapConfigInterface, "LDAPBindDNPassword", 5188a07d286SRatan Gupta std::variant<std::string>(password)); 5198a07d286SRatan Gupta } 5208a07d286SRatan Gupta 5218a07d286SRatan Gupta /** 5228a07d286SRatan Gupta * @brief updates the LDAP BaseDN and updates the 5238a07d286SRatan Gupta json response with the new value. 5248a07d286SRatan Gupta * @param baseDNList baseDN list which needs 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 handleBaseDNPatch(const std::vector<std::string>& baseDNList, 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, baseDNList, 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 base DN"; 5418a07d286SRatan Gupta messages::internalError(asyncResp->res); 5428a07d286SRatan Gupta return; 5438a07d286SRatan Gupta } 5448a07d286SRatan Gupta auto& serverTypeJson = 5458a07d286SRatan Gupta asyncResp->res.jsonValue[ldapServerElementName]; 5468a07d286SRatan Gupta auto& searchSettingsJson = 5478a07d286SRatan Gupta serverTypeJson["LDAPService"]["SearchSettings"]; 5488a07d286SRatan Gupta std::vector<std::string> modifiedBaseDNList = { 5498a07d286SRatan Gupta baseDNList.front()}; 5508a07d286SRatan Gupta searchSettingsJson["BaseDistinguishedNames"] = 5518a07d286SRatan Gupta modifiedBaseDNList; 5528a07d286SRatan Gupta if (baseDNList.size() > 1) 5538a07d286SRatan Gupta { 5548a07d286SRatan Gupta messages::propertyValueModified(asyncResp->res, 5558a07d286SRatan Gupta "BaseDistinguishedNames", 5568a07d286SRatan Gupta baseDNList.front()); 5578a07d286SRatan Gupta } 5588a07d286SRatan Gupta BMCWEB_LOG_DEBUG << "Updated the base DN"; 5598a07d286SRatan Gupta }, 5608a07d286SRatan Gupta ldapDbusService, ldapConfigObject, propertyInterface, "Set", 5618a07d286SRatan Gupta ldapConfigInterface, "LDAPBaseDN", 5628a07d286SRatan Gupta std::variant<std::string>(baseDNList.front())); 5638a07d286SRatan Gupta } 5648a07d286SRatan Gupta /** 5658a07d286SRatan Gupta * @brief updates the LDAP user name attribute and updates the 5668a07d286SRatan Gupta json response with the new value. 5678a07d286SRatan Gupta * @param userNameAttribute attribute to be updated. 5688a07d286SRatan Gupta * @param asyncResp pointer to the JSON response 5698a07d286SRatan Gupta * @param ldapServerElementName Type of LDAP 5708a07d286SRatan Gupta server(openLDAP/ActiveDirectory) 5718a07d286SRatan Gupta */ 5728a07d286SRatan Gupta 5738a07d286SRatan Gupta void handleUserNameAttrPatch(const std::string& userNameAttribute, 5748a07d286SRatan Gupta const std::shared_ptr<AsyncResp>& asyncResp, 5758a07d286SRatan Gupta const std::string& ldapServerElementName, 5768a07d286SRatan Gupta const std::string& ldapConfigObject) 5778a07d286SRatan Gupta { 5788a07d286SRatan Gupta crow::connections::systemBus->async_method_call( 5798a07d286SRatan Gupta [asyncResp, userNameAttribute, 5808a07d286SRatan Gupta ldapServerElementName](const boost::system::error_code ec) { 5818a07d286SRatan Gupta if (ec) 5828a07d286SRatan Gupta { 5838a07d286SRatan Gupta BMCWEB_LOG_DEBUG << "Error Occured in Updating the " 5848a07d286SRatan Gupta "username attribute"; 5858a07d286SRatan Gupta messages::internalError(asyncResp->res); 5868a07d286SRatan Gupta return; 5878a07d286SRatan Gupta } 5888a07d286SRatan Gupta auto& serverTypeJson = 5898a07d286SRatan Gupta asyncResp->res.jsonValue[ldapServerElementName]; 5908a07d286SRatan Gupta auto& searchSettingsJson = 5918a07d286SRatan Gupta serverTypeJson["LDAPService"]["SearchSettings"]; 5928a07d286SRatan Gupta searchSettingsJson["UsernameAttribute"] = userNameAttribute; 5938a07d286SRatan Gupta BMCWEB_LOG_DEBUG << "Updated the user name attr."; 5948a07d286SRatan Gupta }, 5958a07d286SRatan Gupta ldapDbusService, ldapConfigObject, propertyInterface, "Set", 5968a07d286SRatan Gupta ldapConfigInterface, "UserNameAttribute", 5978a07d286SRatan Gupta std::variant<std::string>(userNameAttribute)); 5988a07d286SRatan Gupta } 5998a07d286SRatan Gupta /** 6008a07d286SRatan Gupta * @brief updates the LDAP group attribute and updates the 6018a07d286SRatan Gupta json response with the new value. 6028a07d286SRatan Gupta * @param groupsAttribute attribute to be updated. 6038a07d286SRatan Gupta * @param asyncResp pointer to the JSON response 6048a07d286SRatan Gupta * @param ldapServerElementName Type of LDAP 6058a07d286SRatan Gupta server(openLDAP/ActiveDirectory) 6068a07d286SRatan Gupta */ 6078a07d286SRatan Gupta 6088a07d286SRatan Gupta void handleGroupNameAttrPatch(const std::string& groupsAttribute, 6098a07d286SRatan Gupta const std::shared_ptr<AsyncResp>& asyncResp, 6108a07d286SRatan Gupta const std::string& ldapServerElementName, 6118a07d286SRatan Gupta const std::string& ldapConfigObject) 6128a07d286SRatan Gupta { 6138a07d286SRatan Gupta crow::connections::systemBus->async_method_call( 6148a07d286SRatan Gupta [asyncResp, groupsAttribute, 6158a07d286SRatan Gupta ldapServerElementName](const boost::system::error_code ec) { 6168a07d286SRatan Gupta if (ec) 6178a07d286SRatan Gupta { 6188a07d286SRatan Gupta BMCWEB_LOG_DEBUG << "Error Occured in Updating the " 6198a07d286SRatan Gupta "groupname attribute"; 6208a07d286SRatan Gupta messages::internalError(asyncResp->res); 6218a07d286SRatan Gupta return; 6228a07d286SRatan Gupta } 6238a07d286SRatan Gupta auto& serverTypeJson = 6248a07d286SRatan Gupta asyncResp->res.jsonValue[ldapServerElementName]; 6258a07d286SRatan Gupta auto& searchSettingsJson = 6268a07d286SRatan Gupta serverTypeJson["LDAPService"]["SearchSettings"]; 6278a07d286SRatan Gupta searchSettingsJson["GroupsAttribute"] = groupsAttribute; 6288a07d286SRatan Gupta BMCWEB_LOG_DEBUG << "Updated the groupname attr"; 6298a07d286SRatan Gupta }, 6308a07d286SRatan Gupta ldapDbusService, ldapConfigObject, propertyInterface, "Set", 6318a07d286SRatan Gupta ldapConfigInterface, "GroupNameAttribute", 6328a07d286SRatan Gupta std::variant<std::string>(groupsAttribute)); 6338a07d286SRatan Gupta } 6348a07d286SRatan Gupta /** 6358a07d286SRatan Gupta * @brief updates the LDAP service enable and updates the 6368a07d286SRatan Gupta json response with the new value. 6378a07d286SRatan Gupta * @param input JSON data. 6388a07d286SRatan Gupta * @param asyncResp pointer to the JSON response 6398a07d286SRatan Gupta * @param ldapServerElementName Type of LDAP 6408a07d286SRatan Gupta server(openLDAP/ActiveDirectory) 6418a07d286SRatan Gupta */ 6428a07d286SRatan Gupta 6438a07d286SRatan Gupta void handleServiceEnablePatch(bool serviceEnabled, 6448a07d286SRatan Gupta const std::shared_ptr<AsyncResp>& asyncResp, 6458a07d286SRatan Gupta const std::string& ldapServerElementName, 6468a07d286SRatan Gupta const std::string& ldapConfigObject) 6478a07d286SRatan Gupta { 6488a07d286SRatan Gupta crow::connections::systemBus->async_method_call( 6498a07d286SRatan Gupta [asyncResp, serviceEnabled, 6508a07d286SRatan Gupta ldapServerElementName](const boost::system::error_code ec) { 6518a07d286SRatan Gupta if (ec) 6528a07d286SRatan Gupta { 6538a07d286SRatan Gupta BMCWEB_LOG_DEBUG 6548a07d286SRatan Gupta << "Error Occured in Updating the service enable"; 6558a07d286SRatan Gupta messages::internalError(asyncResp->res); 6568a07d286SRatan Gupta return; 6578a07d286SRatan Gupta } 6588a07d286SRatan Gupta asyncResp->res 6598a07d286SRatan Gupta .jsonValue[ldapServerElementName]["ServiceEnabled"] = 6608a07d286SRatan Gupta serviceEnabled; 6618a07d286SRatan Gupta BMCWEB_LOG_DEBUG << "Updated Service enable = " 6628a07d286SRatan Gupta << serviceEnabled; 6638a07d286SRatan Gupta }, 6648a07d286SRatan Gupta ldapDbusService, ldapConfigObject, propertyInterface, "Set", 6658a07d286SRatan Gupta ldapEnableInterface, "Enabled", std::variant<bool>(serviceEnabled)); 6668a07d286SRatan Gupta } 6678a07d286SRatan Gupta 6688a07d286SRatan Gupta /** 6698a07d286SRatan Gupta * @brief Get the required values from the given JSON, validates the 6708a07d286SRatan Gupta * value and create the LDAP config object. 6718a07d286SRatan Gupta * @param input JSON data 6728a07d286SRatan Gupta * @param asyncResp pointer to the JSON response 6738a07d286SRatan Gupta * @param serverType Type of LDAP server(openLDAP/ActiveDirectory) 6748a07d286SRatan Gupta */ 6758a07d286SRatan Gupta 6768a07d286SRatan Gupta void handleLDAPPatch(nlohmann::json& input, 6778a07d286SRatan Gupta const std::shared_ptr<AsyncResp>& asyncResp, 6788a07d286SRatan Gupta const crow::Request& req, 6798a07d286SRatan Gupta const std::vector<std::string>& params, 6808a07d286SRatan Gupta const std::string& serverType) 6818a07d286SRatan Gupta { 682eb2bbe56SRatan Gupta std::string dbusObjectPath; 683eb2bbe56SRatan Gupta if (serverType == "ActiveDirectory") 684eb2bbe56SRatan Gupta { 685eb2bbe56SRatan Gupta dbusObjectPath = ADConfigObject; 686eb2bbe56SRatan Gupta } 687eb2bbe56SRatan Gupta else if (serverType == "LDAP") 688eb2bbe56SRatan Gupta { 689eb2bbe56SRatan Gupta dbusObjectPath = ldapConfigObject; 690eb2bbe56SRatan Gupta } 691eb2bbe56SRatan Gupta 6928a07d286SRatan Gupta std::optional<nlohmann::json> authentication; 6938a07d286SRatan Gupta std::optional<nlohmann::json> ldapService; 6948a07d286SRatan Gupta std::optional<std::string> accountProviderType; 6958a07d286SRatan Gupta std::optional<std::vector<std::string>> serviceAddressList; 6968a07d286SRatan Gupta std::optional<bool> serviceEnabled; 6978a07d286SRatan Gupta std::optional<std::vector<std::string>> baseDNList; 6988a07d286SRatan Gupta std::optional<std::string> userNameAttribute; 6998a07d286SRatan Gupta std::optional<std::string> groupsAttribute; 7008a07d286SRatan Gupta std::optional<std::string> userName; 7018a07d286SRatan Gupta std::optional<std::string> password; 7028a07d286SRatan Gupta 7038a07d286SRatan Gupta if (!json_util::readJson(input, asyncResp->res, "Authentication", 7048a07d286SRatan Gupta authentication, "LDAPService", ldapService, 7058a07d286SRatan Gupta "ServiceAddresses", serviceAddressList, 7068a07d286SRatan Gupta "AccountProviderType", accountProviderType, 7078a07d286SRatan Gupta "ServiceEnabled", serviceEnabled)) 7088a07d286SRatan Gupta { 7098a07d286SRatan Gupta return; 7108a07d286SRatan Gupta } 7118a07d286SRatan Gupta 7128a07d286SRatan Gupta if (authentication) 7138a07d286SRatan Gupta { 7148a07d286SRatan Gupta parseLDAPAuthenticationJson(*authentication, asyncResp, userName, 7158a07d286SRatan Gupta password); 7168a07d286SRatan Gupta } 7178a07d286SRatan Gupta if (ldapService) 7188a07d286SRatan Gupta { 7198a07d286SRatan Gupta parseLDAPServiceJson(*ldapService, asyncResp, baseDNList, 7208a07d286SRatan Gupta userNameAttribute, groupsAttribute); 7218a07d286SRatan Gupta } 7228a07d286SRatan Gupta if (accountProviderType) 7238a07d286SRatan Gupta { 7248a07d286SRatan Gupta messages::propertyNotWritable(asyncResp->res, 7258a07d286SRatan Gupta "AccountProviderType"); 7268a07d286SRatan Gupta } 7278a07d286SRatan Gupta if (serviceAddressList) 7288a07d286SRatan Gupta { 7298a07d286SRatan Gupta if ((*serviceAddressList).size() == 0) 7308a07d286SRatan Gupta { 7318a07d286SRatan Gupta messages::propertyValueNotInList(asyncResp->res, "[]", 7328a07d286SRatan Gupta "ServiceAddress"); 7338a07d286SRatan Gupta return; 7348a07d286SRatan Gupta } 7358a07d286SRatan Gupta } 7368a07d286SRatan Gupta if (baseDNList) 7378a07d286SRatan Gupta { 7388a07d286SRatan Gupta if ((*baseDNList).size() == 0) 7398a07d286SRatan Gupta { 7408a07d286SRatan Gupta messages::propertyValueNotInList(asyncResp->res, "[]", 7418a07d286SRatan Gupta "BaseDistinguishedNames"); 7428a07d286SRatan Gupta return; 7438a07d286SRatan Gupta } 7448a07d286SRatan Gupta } 7458a07d286SRatan Gupta 7468a07d286SRatan Gupta // nothing to update, then return 7478a07d286SRatan Gupta if (!userName && !password && !serviceAddressList && !baseDNList && 7488a07d286SRatan Gupta !userNameAttribute && !groupsAttribute && !serviceEnabled) 7498a07d286SRatan Gupta { 7508a07d286SRatan Gupta return; 7518a07d286SRatan Gupta } 7528a07d286SRatan Gupta 7538a07d286SRatan Gupta // Get the existing resource first then keep modifying 7548a07d286SRatan Gupta // whenever any property gets updated. 755ab828d7cSRatan Gupta getLDAPConfigData(serverType, [this, asyncResp, userName, password, 756ab828d7cSRatan Gupta baseDNList, userNameAttribute, 757ab828d7cSRatan Gupta groupsAttribute, accountProviderType, 758eb2bbe56SRatan Gupta serviceAddressList, serviceEnabled, 759eb2bbe56SRatan Gupta dbusObjectPath]( 760ab828d7cSRatan Gupta bool success, LDAPConfigData confData, 761ab828d7cSRatan Gupta const std::string& serverType) { 7628a07d286SRatan Gupta if (!success) 7638a07d286SRatan Gupta { 7648a07d286SRatan Gupta messages::internalError(asyncResp->res); 7658a07d286SRatan Gupta return; 7668a07d286SRatan Gupta } 767ab828d7cSRatan Gupta parseLDAPConfigData(asyncResp->res.jsonValue, confData, serverType); 7688a07d286SRatan Gupta if (confData.serviceEnabled) 7698a07d286SRatan Gupta { 7708a07d286SRatan Gupta // Disable the service first and update the rest of 7718a07d286SRatan Gupta // the properties. 7728a07d286SRatan Gupta handleServiceEnablePatch(false, asyncResp, serverType, 773eb2bbe56SRatan Gupta dbusObjectPath); 7748a07d286SRatan Gupta } 7758a07d286SRatan Gupta 7768a07d286SRatan Gupta if (serviceAddressList) 7778a07d286SRatan Gupta { 7788a07d286SRatan Gupta handleServiceAddressPatch(*serviceAddressList, asyncResp, 779eb2bbe56SRatan Gupta serverType, dbusObjectPath); 7808a07d286SRatan Gupta } 7818a07d286SRatan Gupta if (userName) 7828a07d286SRatan Gupta { 7838a07d286SRatan Gupta handleUserNamePatch(*userName, asyncResp, serverType, 784eb2bbe56SRatan Gupta dbusObjectPath); 7858a07d286SRatan Gupta } 7868a07d286SRatan Gupta if (password) 7878a07d286SRatan Gupta { 7888a07d286SRatan Gupta handlePasswordPatch(*password, asyncResp, serverType, 789eb2bbe56SRatan Gupta dbusObjectPath); 7908a07d286SRatan Gupta } 7918a07d286SRatan Gupta 7928a07d286SRatan Gupta if (baseDNList) 7938a07d286SRatan Gupta { 7948a07d286SRatan Gupta handleBaseDNPatch(*baseDNList, asyncResp, serverType, 795eb2bbe56SRatan Gupta dbusObjectPath); 7968a07d286SRatan Gupta } 7978a07d286SRatan Gupta if (userNameAttribute) 7988a07d286SRatan Gupta { 7998a07d286SRatan Gupta handleUserNameAttrPatch(*userNameAttribute, asyncResp, 800eb2bbe56SRatan Gupta serverType, dbusObjectPath); 8018a07d286SRatan Gupta } 8028a07d286SRatan Gupta if (groupsAttribute) 8038a07d286SRatan Gupta { 8048a07d286SRatan Gupta handleGroupNameAttrPatch(*groupsAttribute, asyncResp, 805eb2bbe56SRatan Gupta serverType, dbusObjectPath); 8068a07d286SRatan Gupta } 8078a07d286SRatan Gupta if (serviceEnabled) 8088a07d286SRatan Gupta { 8098a07d286SRatan Gupta // if user has given the value as true then enable 8108a07d286SRatan Gupta // the service. if user has given false then no-op 8118a07d286SRatan Gupta // as service is already stopped. 8128a07d286SRatan Gupta if (*serviceEnabled) 8138a07d286SRatan Gupta { 8148a07d286SRatan Gupta handleServiceEnablePatch(*serviceEnabled, asyncResp, 815eb2bbe56SRatan Gupta serverType, dbusObjectPath); 8168a07d286SRatan Gupta } 8178a07d286SRatan Gupta } 8188a07d286SRatan Gupta else 8198a07d286SRatan Gupta { 8208a07d286SRatan Gupta // if user has not given the service enabled value 8218a07d286SRatan Gupta // then revert it to the same state as it was 8228a07d286SRatan Gupta // before. 8238a07d286SRatan Gupta handleServiceEnablePatch(confData.serviceEnabled, asyncResp, 824eb2bbe56SRatan Gupta serverType, dbusObjectPath); 8258a07d286SRatan Gupta } 8268a07d286SRatan Gupta }); 8278a07d286SRatan Gupta } 8288a07d286SRatan Gupta 82955c7b7a2SEd Tanous void doGet(crow::Response& res, const crow::Request& req, 8301abe55efSEd Tanous const std::vector<std::string>& params) override 8311abe55efSEd Tanous { 8323d958bbcSAppaRao Puli auto asyncResp = std::make_shared<AsyncResp>(res); 8333d958bbcSAppaRao Puli res.jsonValue = { 8343d958bbcSAppaRao Puli {"@odata.context", "/redfish/v1/" 8353d958bbcSAppaRao Puli "$metadata#AccountService.AccountService"}, 8363d958bbcSAppaRao Puli {"@odata.id", "/redfish/v1/AccountService"}, 8373d958bbcSAppaRao Puli {"@odata.type", "#AccountService." 83837cce918SMarri Devender Rao "v1_4_0.AccountService"}, 8393d958bbcSAppaRao Puli {"Id", "AccountService"}, 8403d958bbcSAppaRao Puli {"Name", "Account Service"}, 8413d958bbcSAppaRao Puli {"Description", "Account Service"}, 8423d958bbcSAppaRao Puli {"ServiceEnabled", true}, 843343ff2e1SAppaRao Puli {"MaxPasswordLength", 20}, 8443d958bbcSAppaRao Puli {"Accounts", 8453d958bbcSAppaRao Puli {{"@odata.id", "/redfish/v1/AccountService/Accounts"}}}, 84637cce918SMarri Devender Rao {"Roles", {{"@odata.id", "/redfish/v1/AccountService/Roles"}}}, 84737cce918SMarri Devender Rao {"LDAP", 84837cce918SMarri Devender Rao {{"Certificates", 84937cce918SMarri Devender Rao {{"@odata.id", 85037cce918SMarri Devender Rao "/redfish/v1/AccountService/LDAP/Certificates"}}}}}}; 8513d958bbcSAppaRao Puli crow::connections::systemBus->async_method_call( 8523d958bbcSAppaRao Puli [asyncResp]( 8533d958bbcSAppaRao Puli const boost::system::error_code ec, 8543d958bbcSAppaRao Puli const std::vector<std::pair< 855abf2add6SEd Tanous std::string, std::variant<uint32_t, uint16_t, uint8_t>>>& 8563d958bbcSAppaRao Puli propertiesList) { 8573d958bbcSAppaRao Puli if (ec) 8583d958bbcSAppaRao Puli { 8593d958bbcSAppaRao Puli messages::internalError(asyncResp->res); 8603d958bbcSAppaRao Puli return; 8613d958bbcSAppaRao Puli } 8623d958bbcSAppaRao Puli BMCWEB_LOG_DEBUG << "Got " << propertiesList.size() 8633d958bbcSAppaRao Puli << "properties for AccountService"; 8643d958bbcSAppaRao Puli for (const std::pair<std::string, 865abf2add6SEd Tanous std::variant<uint32_t, uint16_t, uint8_t>>& 8663d958bbcSAppaRao Puli property : propertiesList) 8673d958bbcSAppaRao Puli { 8683d958bbcSAppaRao Puli if (property.first == "MinPasswordLength") 8693d958bbcSAppaRao Puli { 8703d958bbcSAppaRao Puli const uint8_t* value = 871abf2add6SEd Tanous std::get_if<uint8_t>(&property.second); 8723d958bbcSAppaRao Puli if (value != nullptr) 8733d958bbcSAppaRao Puli { 8743d958bbcSAppaRao Puli asyncResp->res.jsonValue["MinPasswordLength"] = 8753d958bbcSAppaRao Puli *value; 8763d958bbcSAppaRao Puli } 8773d958bbcSAppaRao Puli } 8783d958bbcSAppaRao Puli if (property.first == "AccountUnlockTimeout") 8793d958bbcSAppaRao Puli { 8803d958bbcSAppaRao Puli const uint32_t* value = 881abf2add6SEd Tanous std::get_if<uint32_t>(&property.second); 8823d958bbcSAppaRao Puli if (value != nullptr) 8833d958bbcSAppaRao Puli { 8843d958bbcSAppaRao Puli asyncResp->res.jsonValue["AccountLockoutDuration"] = 8853d958bbcSAppaRao Puli *value; 8863d958bbcSAppaRao Puli } 8873d958bbcSAppaRao Puli } 8883d958bbcSAppaRao Puli if (property.first == "MaxLoginAttemptBeforeLockout") 8893d958bbcSAppaRao Puli { 8903d958bbcSAppaRao Puli const uint16_t* value = 891abf2add6SEd Tanous std::get_if<uint16_t>(&property.second); 8923d958bbcSAppaRao Puli if (value != nullptr) 8933d958bbcSAppaRao Puli { 8943d958bbcSAppaRao Puli asyncResp->res 8953d958bbcSAppaRao Puli .jsonValue["AccountLockoutThreshold"] = *value; 8963d958bbcSAppaRao Puli } 8973d958bbcSAppaRao Puli } 8983d958bbcSAppaRao Puli } 8993d958bbcSAppaRao Puli }, 9003d958bbcSAppaRao Puli "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user", 9013d958bbcSAppaRao Puli "org.freedesktop.DBus.Properties", "GetAll", 9023d958bbcSAppaRao Puli "xyz.openbmc_project.User.AccountPolicy"); 9036973a582SRatan Gupta 904ab828d7cSRatan Gupta auto callback = [asyncResp](bool success, LDAPConfigData& confData, 905ab828d7cSRatan Gupta const std::string& ldapType) { 906ab828d7cSRatan Gupta parseLDAPConfigData(asyncResp->res.jsonValue, confData, ldapType); 907ab828d7cSRatan Gupta }; 908ab828d7cSRatan Gupta 909ab828d7cSRatan Gupta getLDAPConfigData("LDAP", callback); 910ab828d7cSRatan Gupta getLDAPConfigData("ActiveDirectory", callback); 9113d958bbcSAppaRao Puli } 9126973a582SRatan Gupta 9133d958bbcSAppaRao Puli void doPatch(crow::Response& res, const crow::Request& req, 9143d958bbcSAppaRao Puli const std::vector<std::string>& params) override 9153d958bbcSAppaRao Puli { 9163d958bbcSAppaRao Puli auto asyncResp = std::make_shared<AsyncResp>(res); 9173d958bbcSAppaRao Puli 9183d958bbcSAppaRao Puli std::optional<uint32_t> unlockTimeout; 9193d958bbcSAppaRao Puli std::optional<uint16_t> lockoutThreshold; 92019fb6e71SRatan Gupta std::optional<uint16_t> minPasswordLength; 92119fb6e71SRatan Gupta std::optional<uint16_t> maxPasswordLength; 9228a07d286SRatan Gupta std::optional<nlohmann::json> ldapObject; 923eb2bbe56SRatan Gupta std::optional<nlohmann::json> activeDirectoryObject; 92419fb6e71SRatan Gupta 9253d958bbcSAppaRao Puli if (!json_util::readJson(req, res, "AccountLockoutDuration", 9263d958bbcSAppaRao Puli unlockTimeout, "AccountLockoutThreshold", 92719fb6e71SRatan Gupta lockoutThreshold, "MaxPasswordLength", 92819fb6e71SRatan Gupta maxPasswordLength, "MinPasswordLength", 929eb2bbe56SRatan Gupta minPasswordLength, "LDAP", ldapObject, 930eb2bbe56SRatan Gupta "ActiveDirectory", activeDirectoryObject)) 9313d958bbcSAppaRao Puli { 9323d958bbcSAppaRao Puli return; 9333d958bbcSAppaRao Puli } 93419fb6e71SRatan Gupta 93519fb6e71SRatan Gupta if (minPasswordLength) 93619fb6e71SRatan Gupta { 93719fb6e71SRatan Gupta messages::propertyNotWritable(asyncResp->res, "MinPasswordLength"); 93819fb6e71SRatan Gupta } 93919fb6e71SRatan Gupta 94019fb6e71SRatan Gupta if (maxPasswordLength) 94119fb6e71SRatan Gupta { 94219fb6e71SRatan Gupta messages::propertyNotWritable(asyncResp->res, "MaxPasswordLength"); 94319fb6e71SRatan Gupta } 94419fb6e71SRatan Gupta 9458a07d286SRatan Gupta if (ldapObject) 9468a07d286SRatan Gupta { 9478a07d286SRatan Gupta handleLDAPPatch(*ldapObject, asyncResp, req, params, "LDAP"); 9488a07d286SRatan Gupta } 9498a07d286SRatan Gupta 950eb2bbe56SRatan Gupta if (activeDirectoryObject) 951eb2bbe56SRatan Gupta { 952eb2bbe56SRatan Gupta handleLDAPPatch(*activeDirectoryObject, asyncResp, req, params, 953eb2bbe56SRatan Gupta "ActiveDirectory"); 954eb2bbe56SRatan Gupta } 955eb2bbe56SRatan Gupta 9563d958bbcSAppaRao Puli if (unlockTimeout) 9573d958bbcSAppaRao Puli { 9583d958bbcSAppaRao Puli crow::connections::systemBus->async_method_call( 9593d958bbcSAppaRao Puli [asyncResp](const boost::system::error_code ec) { 9603d958bbcSAppaRao Puli if (ec) 9613d958bbcSAppaRao Puli { 9623d958bbcSAppaRao Puli messages::internalError(asyncResp->res); 9633d958bbcSAppaRao Puli return; 9643d958bbcSAppaRao Puli } 965add6133bSRatan Gupta messages::success(asyncResp->res); 9663d958bbcSAppaRao Puli }, 9673d958bbcSAppaRao Puli "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user", 9683d958bbcSAppaRao Puli "org.freedesktop.DBus.Properties", "Set", 9693d958bbcSAppaRao Puli "xyz.openbmc_project.User.AccountPolicy", 970abf2add6SEd Tanous "AccountUnlockTimeout", std::variant<uint32_t>(*unlockTimeout)); 9713d958bbcSAppaRao Puli } 9723d958bbcSAppaRao Puli if (lockoutThreshold) 9733d958bbcSAppaRao Puli { 9743d958bbcSAppaRao Puli crow::connections::systemBus->async_method_call( 9753d958bbcSAppaRao Puli [asyncResp](const boost::system::error_code ec) { 9763d958bbcSAppaRao Puli if (ec) 9773d958bbcSAppaRao Puli { 9783d958bbcSAppaRao Puli messages::internalError(asyncResp->res); 9793d958bbcSAppaRao Puli return; 9803d958bbcSAppaRao Puli } 981add6133bSRatan Gupta messages::success(asyncResp->res); 9823d958bbcSAppaRao Puli }, 9833d958bbcSAppaRao Puli "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user", 9843d958bbcSAppaRao Puli "org.freedesktop.DBus.Properties", "Set", 9853d958bbcSAppaRao Puli "xyz.openbmc_project.User.AccountPolicy", 9863d958bbcSAppaRao Puli "MaxLoginAttemptBeforeLockout", 987abf2add6SEd Tanous std::variant<uint16_t>(*lockoutThreshold)); 9883d958bbcSAppaRao Puli } 98988d16c9aSLewanczyk, Dawid } 99088d16c9aSLewanczyk, Dawid }; 991f00032dbSTanous 992b9b2e0b2SEd Tanous class AccountsCollection : public Node 993b9b2e0b2SEd Tanous { 994b9b2e0b2SEd Tanous public: 995b9b2e0b2SEd Tanous AccountsCollection(CrowApp& app) : 996b9b2e0b2SEd Tanous Node(app, "/redfish/v1/AccountService/Accounts/") 997b9b2e0b2SEd Tanous { 998b9b2e0b2SEd Tanous entityPrivileges = { 999b9b2e0b2SEd Tanous {boost::beast::http::verb::get, 1000b9b2e0b2SEd Tanous {{"ConfigureUsers"}, {"ConfigureManager"}}}, 1001b9b2e0b2SEd Tanous {boost::beast::http::verb::head, {{"Login"}}}, 1002b9b2e0b2SEd Tanous {boost::beast::http::verb::patch, {{"ConfigureUsers"}}}, 1003b9b2e0b2SEd Tanous {boost::beast::http::verb::put, {{"ConfigureUsers"}}}, 1004b9b2e0b2SEd Tanous {boost::beast::http::verb::delete_, {{"ConfigureUsers"}}}, 1005b9b2e0b2SEd Tanous {boost::beast::http::verb::post, {{"ConfigureUsers"}}}}; 1006b9b2e0b2SEd Tanous } 1007b9b2e0b2SEd Tanous 1008b9b2e0b2SEd Tanous private: 1009b9b2e0b2SEd Tanous void doGet(crow::Response& res, const crow::Request& req, 1010b9b2e0b2SEd Tanous const std::vector<std::string>& params) override 1011b9b2e0b2SEd Tanous { 1012b9b2e0b2SEd Tanous auto asyncResp = std::make_shared<AsyncResp>(res); 10130f74e643SEd Tanous res.jsonValue = {{"@odata.context", 10140f74e643SEd Tanous "/redfish/v1/" 10150f74e643SEd Tanous "$metadata#ManagerAccountCollection." 10160f74e643SEd Tanous "ManagerAccountCollection"}, 10170f74e643SEd Tanous {"@odata.id", "/redfish/v1/AccountService/Accounts"}, 10180f74e643SEd Tanous {"@odata.type", "#ManagerAccountCollection." 10190f74e643SEd Tanous "ManagerAccountCollection"}, 10200f74e643SEd Tanous {"Name", "Accounts Collection"}, 10210f74e643SEd Tanous {"Description", "BMC User Accounts"}}; 10220f74e643SEd Tanous 1023b9b2e0b2SEd Tanous crow::connections::systemBus->async_method_call( 1024b9b2e0b2SEd Tanous [asyncResp](const boost::system::error_code ec, 1025b9b2e0b2SEd Tanous const ManagedObjectType& users) { 1026b9b2e0b2SEd Tanous if (ec) 1027b9b2e0b2SEd Tanous { 1028f12894f8SJason M. Bills messages::internalError(asyncResp->res); 1029b9b2e0b2SEd Tanous return; 1030b9b2e0b2SEd Tanous } 1031b9b2e0b2SEd Tanous 1032b9b2e0b2SEd Tanous nlohmann::json& memberArray = 1033b9b2e0b2SEd Tanous asyncResp->res.jsonValue["Members"]; 1034b9b2e0b2SEd Tanous memberArray = nlohmann::json::array(); 1035b9b2e0b2SEd Tanous 1036b9b2e0b2SEd Tanous asyncResp->res.jsonValue["Members@odata.count"] = users.size(); 1037b9b2e0b2SEd Tanous for (auto& user : users) 1038b9b2e0b2SEd Tanous { 1039b9b2e0b2SEd Tanous const std::string& path = 1040b9b2e0b2SEd Tanous static_cast<const std::string&>(user.first); 1041b9b2e0b2SEd Tanous std::size_t lastIndex = path.rfind("/"); 1042b9b2e0b2SEd Tanous if (lastIndex == std::string::npos) 1043b9b2e0b2SEd Tanous { 1044b9b2e0b2SEd Tanous lastIndex = 0; 1045b9b2e0b2SEd Tanous } 1046b9b2e0b2SEd Tanous else 1047b9b2e0b2SEd Tanous { 1048b9b2e0b2SEd Tanous lastIndex += 1; 1049b9b2e0b2SEd Tanous } 1050b9b2e0b2SEd Tanous memberArray.push_back( 1051b9b2e0b2SEd Tanous {{"@odata.id", "/redfish/v1/AccountService/Accounts/" + 1052b9b2e0b2SEd Tanous path.substr(lastIndex)}}); 1053b9b2e0b2SEd Tanous } 1054b9b2e0b2SEd Tanous }, 1055b9b2e0b2SEd Tanous "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user", 1056b9b2e0b2SEd Tanous "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 1057b9b2e0b2SEd Tanous } 105804ae99ecSEd Tanous void doPost(crow::Response& res, const crow::Request& req, 105904ae99ecSEd Tanous const std::vector<std::string>& params) override 106004ae99ecSEd Tanous { 106104ae99ecSEd Tanous auto asyncResp = std::make_shared<AsyncResp>(res); 106204ae99ecSEd Tanous 10639712f8acSEd Tanous std::string username; 10649712f8acSEd Tanous std::string password; 1065a24526dcSEd Tanous std::optional<std::string> roleId("User"); 1066a24526dcSEd Tanous std::optional<bool> enabled = true; 10679712f8acSEd Tanous if (!json_util::readJson(req, res, "UserName", username, "Password", 10689712f8acSEd Tanous password, "RoleId", roleId, "Enabled", 10699712f8acSEd Tanous enabled)) 107004ae99ecSEd Tanous { 107104ae99ecSEd Tanous return; 107204ae99ecSEd Tanous } 107304ae99ecSEd Tanous 1074*54fc587aSNagaraju Goruganti std::string priv = getPrivilegeFromRoleId(*roleId); 107584e12cb7SAppaRao Puli if (priv.empty()) 107604ae99ecSEd Tanous { 1077f12894f8SJason M. Bills messages::propertyValueNotInList(asyncResp->res, *roleId, "RoleId"); 107804ae99ecSEd Tanous return; 107904ae99ecSEd Tanous } 10809712f8acSEd Tanous roleId = priv; 108104ae99ecSEd Tanous 108204ae99ecSEd Tanous crow::connections::systemBus->async_method_call( 10839712f8acSEd Tanous [asyncResp, username, password{std::move(password)}]( 108404ae99ecSEd Tanous const boost::system::error_code ec) { 108504ae99ecSEd Tanous if (ec) 108604ae99ecSEd Tanous { 108704ae99ecSEd Tanous messages::resourceAlreadyExists( 1088f12894f8SJason M. Bills asyncResp->res, "#ManagerAccount.v1_0_3.ManagerAccount", 1089f12894f8SJason M. Bills "UserName", username); 109004ae99ecSEd Tanous return; 109104ae99ecSEd Tanous } 109204ae99ecSEd Tanous 109304ae99ecSEd Tanous if (!pamUpdatePassword(username, password)) 109404ae99ecSEd Tanous { 1095*54fc587aSNagaraju Goruganti // At this point we have a user that's been created, but 1096*54fc587aSNagaraju Goruganti // the password set failed. Something is wrong, so 1097*54fc587aSNagaraju Goruganti // delete the user that we've already created 109804ae99ecSEd Tanous crow::connections::systemBus->async_method_call( 109904ae99ecSEd Tanous [asyncResp](const boost::system::error_code ec) { 110004ae99ecSEd Tanous if (ec) 110104ae99ecSEd Tanous { 1102f12894f8SJason M. Bills messages::internalError(asyncResp->res); 110304ae99ecSEd Tanous return; 110404ae99ecSEd Tanous } 110504ae99ecSEd Tanous 1106f12894f8SJason M. Bills messages::invalidObject(asyncResp->res, "Password"); 110704ae99ecSEd Tanous }, 110804ae99ecSEd Tanous "xyz.openbmc_project.User.Manager", 110904ae99ecSEd Tanous "/xyz/openbmc_project/user/" + username, 111004ae99ecSEd Tanous "xyz.openbmc_project.Object.Delete", "Delete"); 111104ae99ecSEd Tanous 111204ae99ecSEd Tanous BMCWEB_LOG_ERROR << "pamUpdatePassword Failed"; 111304ae99ecSEd Tanous return; 111404ae99ecSEd Tanous } 111504ae99ecSEd Tanous 1116f12894f8SJason M. Bills messages::created(asyncResp->res); 111704ae99ecSEd Tanous asyncResp->res.addHeader( 111804ae99ecSEd Tanous "Location", 111904ae99ecSEd Tanous "/redfish/v1/AccountService/Accounts/" + username); 112004ae99ecSEd Tanous }, 112104ae99ecSEd Tanous "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user", 11229712f8acSEd Tanous "xyz.openbmc_project.User.Manager", "CreateUser", username, 112304ae99ecSEd Tanous std::array<const char*, 4>{"ipmi", "redfish", "ssh", "web"}, 11249712f8acSEd Tanous *roleId, *enabled); 112504ae99ecSEd Tanous } 1126b9b2e0b2SEd Tanous }; 1127b9b2e0b2SEd Tanous 1128b9b2e0b2SEd Tanous class ManagerAccount : public Node 1129b9b2e0b2SEd Tanous { 1130b9b2e0b2SEd Tanous public: 1131b9b2e0b2SEd Tanous ManagerAccount(CrowApp& app) : 1132b9b2e0b2SEd Tanous Node(app, "/redfish/v1/AccountService/Accounts/<str>/", std::string()) 1133b9b2e0b2SEd Tanous { 1134b9b2e0b2SEd Tanous entityPrivileges = { 1135b9b2e0b2SEd Tanous {boost::beast::http::verb::get, 1136b9b2e0b2SEd Tanous {{"ConfigureUsers"}, {"ConfigureManager"}, {"ConfigureSelf"}}}, 1137b9b2e0b2SEd Tanous {boost::beast::http::verb::head, {{"Login"}}}, 1138b9b2e0b2SEd Tanous {boost::beast::http::verb::patch, {{"ConfigureUsers"}}}, 1139b9b2e0b2SEd Tanous {boost::beast::http::verb::put, {{"ConfigureUsers"}}}, 1140b9b2e0b2SEd Tanous {boost::beast::http::verb::delete_, {{"ConfigureUsers"}}}, 1141b9b2e0b2SEd Tanous {boost::beast::http::verb::post, {{"ConfigureUsers"}}}}; 1142b9b2e0b2SEd Tanous } 1143b9b2e0b2SEd Tanous 1144b9b2e0b2SEd Tanous private: 1145b9b2e0b2SEd Tanous void doGet(crow::Response& res, const crow::Request& req, 1146b9b2e0b2SEd Tanous const std::vector<std::string>& params) override 1147b9b2e0b2SEd Tanous { 11480f74e643SEd Tanous res.jsonValue = { 11490f74e643SEd Tanous {"@odata.context", 11500f74e643SEd Tanous "/redfish/v1/$metadata#ManagerAccount.ManagerAccount"}, 11510f74e643SEd Tanous {"@odata.type", "#ManagerAccount.v1_0_3.ManagerAccount"}, 11520f74e643SEd Tanous {"Name", "User Account"}, 11530f74e643SEd Tanous {"Description", "User Account"}, 11540f74e643SEd Tanous {"Password", nullptr}, 115584e12cb7SAppaRao Puli {"RoleId", "Administrator"}}; 11560f74e643SEd Tanous 1157b9b2e0b2SEd Tanous auto asyncResp = std::make_shared<AsyncResp>(res); 1158b9b2e0b2SEd Tanous 1159b9b2e0b2SEd Tanous if (params.size() != 1) 1160b9b2e0b2SEd Tanous { 1161f12894f8SJason M. Bills messages::internalError(asyncResp->res); 1162b9b2e0b2SEd Tanous return; 1163b9b2e0b2SEd Tanous } 1164b9b2e0b2SEd Tanous 1165b9b2e0b2SEd Tanous crow::connections::systemBus->async_method_call( 1166b9b2e0b2SEd Tanous [asyncResp, accountName{std::string(params[0])}]( 1167b9b2e0b2SEd Tanous const boost::system::error_code ec, 1168b9b2e0b2SEd Tanous const ManagedObjectType& users) { 1169b9b2e0b2SEd Tanous if (ec) 1170b9b2e0b2SEd Tanous { 1171f12894f8SJason M. Bills messages::internalError(asyncResp->res); 1172b9b2e0b2SEd Tanous return; 1173b9b2e0b2SEd Tanous } 117484e12cb7SAppaRao Puli auto userIt = users.begin(); 1175b9b2e0b2SEd Tanous 117684e12cb7SAppaRao Puli for (; userIt != users.end(); userIt++) 1177b9b2e0b2SEd Tanous { 117884e12cb7SAppaRao Puli if (boost::ends_with(userIt->first.str, "/" + accountName)) 1179b9b2e0b2SEd Tanous { 118084e12cb7SAppaRao Puli break; 1181b9b2e0b2SEd Tanous } 1182b9b2e0b2SEd Tanous } 118384e12cb7SAppaRao Puli if (userIt == users.end()) 1184b9b2e0b2SEd Tanous { 118584e12cb7SAppaRao Puli messages::resourceNotFound(asyncResp->res, "ManagerAccount", 118684e12cb7SAppaRao Puli accountName); 118784e12cb7SAppaRao Puli return; 118884e12cb7SAppaRao Puli } 118984e12cb7SAppaRao Puli for (const auto& interface : userIt->second) 119065b0dc32SEd Tanous { 119165b0dc32SEd Tanous if (interface.first == 119265b0dc32SEd Tanous "xyz.openbmc_project.User.Attributes") 119365b0dc32SEd Tanous { 119465b0dc32SEd Tanous for (const auto& property : interface.second) 119565b0dc32SEd Tanous { 119665b0dc32SEd Tanous if (property.first == "UserEnabled") 119765b0dc32SEd Tanous { 119865b0dc32SEd Tanous const bool* userEnabled = 1199abf2add6SEd Tanous std::get_if<bool>(&property.second); 120065b0dc32SEd Tanous if (userEnabled == nullptr) 120165b0dc32SEd Tanous { 120265b0dc32SEd Tanous BMCWEB_LOG_ERROR 120365b0dc32SEd Tanous << "UserEnabled wasn't a bool"; 120484e12cb7SAppaRao Puli messages::internalError(asyncResp->res); 120584e12cb7SAppaRao Puli return; 120665b0dc32SEd Tanous } 120765b0dc32SEd Tanous asyncResp->res.jsonValue["Enabled"] = 120865b0dc32SEd Tanous *userEnabled; 120965b0dc32SEd Tanous } 121065b0dc32SEd Tanous else if (property.first == 121165b0dc32SEd Tanous "UserLockedForFailedAttempt") 121265b0dc32SEd Tanous { 121365b0dc32SEd Tanous const bool* userLocked = 1214abf2add6SEd Tanous std::get_if<bool>(&property.second); 121565b0dc32SEd Tanous if (userLocked == nullptr) 121665b0dc32SEd Tanous { 121784e12cb7SAppaRao Puli BMCWEB_LOG_ERROR << "UserLockedForF" 121884e12cb7SAppaRao Puli "ailedAttempt " 121984e12cb7SAppaRao Puli "wasn't a bool"; 122084e12cb7SAppaRao Puli messages::internalError(asyncResp->res); 122184e12cb7SAppaRao Puli return; 122265b0dc32SEd Tanous } 122365b0dc32SEd Tanous asyncResp->res.jsonValue["Locked"] = 122465b0dc32SEd Tanous *userLocked; 122524c8542dSRatan Gupta asyncResp->res.jsonValue 122624c8542dSRatan Gupta ["Locked@Redfish.AllowableValues"] = { 12274d64ce34SGunnar Mills "false"}; 122865b0dc32SEd Tanous } 122984e12cb7SAppaRao Puli else if (property.first == "UserPrivilege") 123084e12cb7SAppaRao Puli { 1231*54fc587aSNagaraju Goruganti const std::string* userPrivPtr = 1232abf2add6SEd Tanous std::get_if<std::string>(&property.second); 1233*54fc587aSNagaraju Goruganti if (userPrivPtr == nullptr) 123484e12cb7SAppaRao Puli { 123584e12cb7SAppaRao Puli BMCWEB_LOG_ERROR 123684e12cb7SAppaRao Puli << "UserPrivilege wasn't a " 123784e12cb7SAppaRao Puli "string"; 123884e12cb7SAppaRao Puli messages::internalError(asyncResp->res); 123984e12cb7SAppaRao Puli return; 124084e12cb7SAppaRao Puli } 1241*54fc587aSNagaraju Goruganti std::string role = 1242*54fc587aSNagaraju Goruganti getRoleIdFromPrivilege(*userPrivPtr); 1243*54fc587aSNagaraju Goruganti if (role.empty()) 124484e12cb7SAppaRao Puli { 124584e12cb7SAppaRao Puli BMCWEB_LOG_ERROR << "Invalid user role"; 124684e12cb7SAppaRao Puli messages::internalError(asyncResp->res); 124784e12cb7SAppaRao Puli return; 124884e12cb7SAppaRao Puli } 1249*54fc587aSNagaraju Goruganti asyncResp->res.jsonValue["RoleId"] = role; 125084e12cb7SAppaRao Puli 125184e12cb7SAppaRao Puli asyncResp->res.jsonValue["Links"]["Role"] = { 125284e12cb7SAppaRao Puli {"@odata.id", "/redfish/v1/AccountService/" 125384e12cb7SAppaRao Puli "Roles/" + 1254*54fc587aSNagaraju Goruganti role}}; 125584e12cb7SAppaRao Puli } 125665b0dc32SEd Tanous } 125765b0dc32SEd Tanous } 125865b0dc32SEd Tanous } 125965b0dc32SEd Tanous 1260b9b2e0b2SEd Tanous asyncResp->res.jsonValue["@odata.id"] = 126184e12cb7SAppaRao Puli "/redfish/v1/AccountService/Accounts/" + accountName; 1262b9b2e0b2SEd Tanous asyncResp->res.jsonValue["Id"] = accountName; 1263b9b2e0b2SEd Tanous asyncResp->res.jsonValue["UserName"] = accountName; 1264b9b2e0b2SEd Tanous }, 1265b9b2e0b2SEd Tanous "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user", 1266b9b2e0b2SEd Tanous "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 1267b9b2e0b2SEd Tanous } 1268a840879dSEd Tanous 1269a840879dSEd Tanous void doPatch(crow::Response& res, const crow::Request& req, 1270a840879dSEd Tanous const std::vector<std::string>& params) override 1271a840879dSEd Tanous { 1272a840879dSEd Tanous auto asyncResp = std::make_shared<AsyncResp>(res); 1273a840879dSEd Tanous if (params.size() != 1) 1274a840879dSEd Tanous { 1275f12894f8SJason M. Bills messages::internalError(asyncResp->res); 1276a840879dSEd Tanous return; 1277a840879dSEd Tanous } 1278a840879dSEd Tanous 1279a24526dcSEd Tanous std::optional<std::string> newUserName; 1280a24526dcSEd Tanous std::optional<std::string> password; 1281a24526dcSEd Tanous std::optional<bool> enabled; 1282a24526dcSEd Tanous std::optional<std::string> roleId; 128324c8542dSRatan Gupta std::optional<bool> locked; 128484e12cb7SAppaRao Puli if (!json_util::readJson(req, res, "UserName", newUserName, "Password", 128524c8542dSRatan Gupta password, "RoleId", roleId, "Enabled", enabled, 128624c8542dSRatan Gupta "Locked", locked)) 1287a840879dSEd Tanous { 1288a840879dSEd Tanous return; 1289a840879dSEd Tanous } 1290a840879dSEd Tanous 129184e12cb7SAppaRao Puli const std::string& username = params[0]; 129284e12cb7SAppaRao Puli 129384e12cb7SAppaRao Puli if (!newUserName) 1294a840879dSEd Tanous { 1295*54fc587aSNagaraju Goruganti // If the username isn't being updated, we can update the 1296*54fc587aSNagaraju Goruganti // properties directly 129724c8542dSRatan Gupta updateUserProperties(asyncResp, username, password, enabled, roleId, 129824c8542dSRatan Gupta locked); 129984e12cb7SAppaRao Puli return; 130084e12cb7SAppaRao Puli } 130184e12cb7SAppaRao Puli else 130284e12cb7SAppaRao Puli { 130384e12cb7SAppaRao Puli crow::connections::systemBus->async_method_call( 130484e12cb7SAppaRao Puli [this, asyncResp, username, password(std::move(password)), 130584e12cb7SAppaRao Puli roleId(std::move(roleId)), enabled(std::move(enabled)), 130624c8542dSRatan Gupta newUser{std::string(*newUserName)}, locked(std::move(locked))]( 130784e12cb7SAppaRao Puli const boost::system::error_code ec) { 130884e12cb7SAppaRao Puli if (ec) 130984e12cb7SAppaRao Puli { 131084e12cb7SAppaRao Puli BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec; 1311a840879dSEd Tanous messages::resourceNotFound( 131284e12cb7SAppaRao Puli asyncResp->res, 131384e12cb7SAppaRao Puli "#ManagerAccount.v1_0_3.ManagerAccount", username); 1314a840879dSEd Tanous return; 1315a840879dSEd Tanous } 1316a840879dSEd Tanous 131784e12cb7SAppaRao Puli updateUserProperties(asyncResp, newUser, password, enabled, 131824c8542dSRatan Gupta roleId, locked); 131984e12cb7SAppaRao Puli }, 132084e12cb7SAppaRao Puli "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user", 132184e12cb7SAppaRao Puli "xyz.openbmc_project.User.Manager", "RenameUser", username, 132284e12cb7SAppaRao Puli *newUserName); 132384e12cb7SAppaRao Puli } 132484e12cb7SAppaRao Puli } 132584e12cb7SAppaRao Puli 132684e12cb7SAppaRao Puli void updateUserProperties(std::shared_ptr<AsyncResp> asyncResp, 132784e12cb7SAppaRao Puli const std::string& username, 1328a24526dcSEd Tanous std::optional<std::string> password, 1329a24526dcSEd Tanous std::optional<bool> enabled, 133024c8542dSRatan Gupta std::optional<std::string> roleId, 133124c8542dSRatan Gupta std::optional<bool> locked) 133284e12cb7SAppaRao Puli { 13339712f8acSEd Tanous if (password) 1334a840879dSEd Tanous { 13359712f8acSEd Tanous if (!pamUpdatePassword(username, *password)) 1336a840879dSEd Tanous { 1337a840879dSEd Tanous BMCWEB_LOG_ERROR << "pamUpdatePassword Failed"; 1338f12894f8SJason M. Bills messages::internalError(asyncResp->res); 1339a840879dSEd Tanous return; 1340a840879dSEd Tanous } 1341a840879dSEd Tanous } 1342a840879dSEd Tanous 134324c8542dSRatan Gupta std::string dbusObjectPath = "/xyz/openbmc_project/user/" + username; 134424c8542dSRatan Gupta dbus::utility::escapePathForDbus(dbusObjectPath); 134524c8542dSRatan Gupta 134622c33710SRatan Gupta dbus::utility::checkDbusPathExists( 134724c8542dSRatan Gupta dbusObjectPath, 134824c8542dSRatan Gupta [dbusObjectPath(std::move(dbusObjectPath)), username, 134924c8542dSRatan Gupta password(std::move(password)), roleId(std::move(roleId)), 135024c8542dSRatan Gupta enabled(std::move(enabled)), locked(std::move(locked)), 135124c8542dSRatan Gupta asyncResp{std::move(asyncResp)}](int rc) { 135224c8542dSRatan Gupta if (!rc) 135324c8542dSRatan Gupta { 135424c8542dSRatan Gupta messages::invalidObject(asyncResp->res, username.c_str()); 135524c8542dSRatan Gupta return; 135624c8542dSRatan Gupta } 13579712f8acSEd Tanous if (enabled) 1358a840879dSEd Tanous { 1359a840879dSEd Tanous crow::connections::systemBus->async_method_call( 1360a840879dSEd Tanous [asyncResp](const boost::system::error_code ec) { 1361a840879dSEd Tanous if (ec) 1362a840879dSEd Tanous { 136324c8542dSRatan Gupta BMCWEB_LOG_ERROR << "D-Bus responses error: " 136424c8542dSRatan Gupta << ec; 1365f12894f8SJason M. Bills messages::internalError(asyncResp->res); 1366a840879dSEd Tanous return; 1367a840879dSEd Tanous } 136884e12cb7SAppaRao Puli messages::success(asyncResp->res); 136984e12cb7SAppaRao Puli return; 137084e12cb7SAppaRao Puli }, 137184e12cb7SAppaRao Puli "xyz.openbmc_project.User.Manager", 137224c8542dSRatan Gupta dbusObjectPath.c_str(), 137384e12cb7SAppaRao Puli "org.freedesktop.DBus.Properties", "Set", 137484e12cb7SAppaRao Puli "xyz.openbmc_project.User.Attributes", "UserEnabled", 1375abf2add6SEd Tanous std::variant<bool>{*enabled}); 137684e12cb7SAppaRao Puli } 137784e12cb7SAppaRao Puli 137884e12cb7SAppaRao Puli if (roleId) 137984e12cb7SAppaRao Puli { 1380*54fc587aSNagaraju Goruganti std::string priv = getPrivilegeFromRoleId(*roleId); 138184e12cb7SAppaRao Puli if (priv.empty()) 138284e12cb7SAppaRao Puli { 138324c8542dSRatan Gupta messages::propertyValueNotInList(asyncResp->res, 138424c8542dSRatan Gupta *roleId, "RoleId"); 138584e12cb7SAppaRao Puli return; 138684e12cb7SAppaRao Puli } 138784e12cb7SAppaRao Puli 138884e12cb7SAppaRao Puli crow::connections::systemBus->async_method_call( 138984e12cb7SAppaRao Puli [asyncResp](const boost::system::error_code ec) { 139084e12cb7SAppaRao Puli if (ec) 139184e12cb7SAppaRao Puli { 139224c8542dSRatan Gupta BMCWEB_LOG_ERROR << "D-Bus responses error: " 139324c8542dSRatan Gupta << ec; 139484e12cb7SAppaRao Puli messages::internalError(asyncResp->res); 139584e12cb7SAppaRao Puli return; 139684e12cb7SAppaRao Puli } 1397f12894f8SJason M. Bills messages::success(asyncResp->res); 1398a840879dSEd Tanous }, 1399a840879dSEd Tanous "xyz.openbmc_project.User.Manager", 140024c8542dSRatan Gupta dbusObjectPath.c_str(), 1401a840879dSEd Tanous "org.freedesktop.DBus.Properties", "Set", 140284e12cb7SAppaRao Puli "xyz.openbmc_project.User.Attributes", "UserPrivilege", 1403abf2add6SEd Tanous std::variant<std::string>{priv}); 1404a840879dSEd Tanous } 140524c8542dSRatan Gupta 140624c8542dSRatan Gupta if (locked) 140724c8542dSRatan Gupta { 140824c8542dSRatan Gupta // admin can unlock the account which is locked by 1409*54fc587aSNagaraju Goruganti // successive authentication failures but admin should 1410*54fc587aSNagaraju Goruganti // not be allowed to lock an account. 141124c8542dSRatan Gupta if (*locked) 141224c8542dSRatan Gupta { 141324c8542dSRatan Gupta messages::propertyValueNotInList(asyncResp->res, "true", 141424c8542dSRatan Gupta "Locked"); 141524c8542dSRatan Gupta return; 141624c8542dSRatan Gupta } 141724c8542dSRatan Gupta 141824c8542dSRatan Gupta crow::connections::systemBus->async_method_call( 141924c8542dSRatan Gupta [asyncResp](const boost::system::error_code ec) { 142024c8542dSRatan Gupta if (ec) 142124c8542dSRatan Gupta { 142224c8542dSRatan Gupta BMCWEB_LOG_ERROR << "D-Bus responses error: " 142324c8542dSRatan Gupta << ec; 142424c8542dSRatan Gupta messages::internalError(asyncResp->res); 142524c8542dSRatan Gupta return; 142624c8542dSRatan Gupta } 142724c8542dSRatan Gupta messages::success(asyncResp->res); 142824c8542dSRatan Gupta return; 142924c8542dSRatan Gupta }, 143024c8542dSRatan Gupta "xyz.openbmc_project.User.Manager", 143124c8542dSRatan Gupta dbusObjectPath.c_str(), 143224c8542dSRatan Gupta "org.freedesktop.DBus.Properties", "Set", 143324c8542dSRatan Gupta "xyz.openbmc_project.User.Attributes", 143424c8542dSRatan Gupta "UserLockedForFailedAttempt", 143524c8542dSRatan Gupta sdbusplus::message::variant<bool>{*locked}); 143624c8542dSRatan Gupta } 143724c8542dSRatan Gupta }); 1438a840879dSEd Tanous } 143906e086d9SEd Tanous 144006e086d9SEd Tanous void doDelete(crow::Response& res, const crow::Request& req, 144106e086d9SEd Tanous const std::vector<std::string>& params) override 144206e086d9SEd Tanous { 144306e086d9SEd Tanous auto asyncResp = std::make_shared<AsyncResp>(res); 144406e086d9SEd Tanous 144506e086d9SEd Tanous if (params.size() != 1) 144606e086d9SEd Tanous { 1447f12894f8SJason M. Bills messages::internalError(asyncResp->res); 144806e086d9SEd Tanous return; 144906e086d9SEd Tanous } 145006e086d9SEd Tanous 145106e086d9SEd Tanous const std::string userPath = "/xyz/openbmc_project/user/" + params[0]; 145206e086d9SEd Tanous 145306e086d9SEd Tanous crow::connections::systemBus->async_method_call( 145406e086d9SEd Tanous [asyncResp, username{std::move(params[0])}]( 145506e086d9SEd Tanous const boost::system::error_code ec) { 145606e086d9SEd Tanous if (ec) 145706e086d9SEd Tanous { 145806e086d9SEd Tanous messages::resourceNotFound( 1459f12894f8SJason M. Bills asyncResp->res, "#ManagerAccount.v1_0_3.ManagerAccount", 1460f12894f8SJason M. Bills username); 146106e086d9SEd Tanous return; 146206e086d9SEd Tanous } 146306e086d9SEd Tanous 1464f12894f8SJason M. Bills messages::accountRemoved(asyncResp->res); 146506e086d9SEd Tanous }, 146606e086d9SEd Tanous "xyz.openbmc_project.User.Manager", userPath, 146706e086d9SEd Tanous "xyz.openbmc_project.Object.Delete", "Delete"); 146806e086d9SEd Tanous } 146984e12cb7SAppaRao Puli }; 147088d16c9aSLewanczyk, Dawid 147188d16c9aSLewanczyk, Dawid } // namespace redfish 1472