1*40e9b92eSEd Tanous // SPDX-License-Identifier: Apache-2.0 2*40e9b92eSEd Tanous // SPDX-FileCopyrightText: Copyright OpenBMC Authors 3*40e9b92eSEd Tanous // SPDX-FileCopyrightText: Copyright 2018 Intel Corporation 488d16c9aSLewanczyk, Dawid #pragma once 588d16c9aSLewanczyk, Dawid 63ccb3adbSEd Tanous #include "app.hpp" 7a0735a4eSGunnar Mills #include "boost_formatters.hpp" 81aa375b8SEd Tanous #include "certificate_service.hpp" 93ccb3adbSEd Tanous #include "dbus_utility.hpp" 103ccb3adbSEd Tanous #include "error_messages.hpp" 110ec8b83dSEd Tanous #include "generated/enums/account_service.hpp" 123ccb3adbSEd Tanous #include "persistent_data.hpp" 133ccb3adbSEd Tanous #include "query.hpp" 140ec8b83dSEd Tanous #include "registries/privilege_registry.hpp" 153281bcf1SEd Tanous #include "sessions.hpp" 161aa375b8SEd Tanous #include "utils/collection.hpp" 173ccb3adbSEd Tanous #include "utils/dbus_utils.hpp" 183ccb3adbSEd Tanous #include "utils/json_utils.hpp" 190ec8b83dSEd Tanous 201aa375b8SEd Tanous #include <boost/url/format.hpp> 211aa375b8SEd Tanous #include <boost/url/url.hpp> 221e1e598dSJonathan Doman #include <sdbusplus/asio/property.hpp> 23d1bde9e5SKrzysztof Grobelny #include <sdbusplus/unpack_properties.hpp> 241214b7e7SGunnar Mills 252b73119cSGeorge Liu #include <array> 261aa375b8SEd Tanous #include <memory> 27c7229815SAbhishek Patel #include <optional> 283544d2a7SEd Tanous #include <ranges> 29c7229815SAbhishek Patel #include <string> 302b73119cSGeorge Liu #include <string_view> 3120fa6a2cSEd Tanous #include <utility> 32c7229815SAbhishek Patel #include <vector> 33c7229815SAbhishek Patel 341abe55efSEd Tanous namespace redfish 351abe55efSEd Tanous { 3688d16c9aSLewanczyk, Dawid 3723a21a1cSEd Tanous constexpr const char* ldapConfigObjectName = 386973a582SRatan Gupta "/xyz/openbmc_project/user/ldap/openldap"; 392c70f800SEd Tanous constexpr const char* adConfigObject = 40ab828d7cSRatan Gupta "/xyz/openbmc_project/user/ldap/active_directory"; 41ab828d7cSRatan Gupta 42b477fd44SP Dheeraj Srujan Kumar constexpr const char* rootUserDbusPath = "/xyz/openbmc_project/user/"; 436973a582SRatan Gupta constexpr const char* ldapRootObject = "/xyz/openbmc_project/user/ldap"; 446973a582SRatan Gupta constexpr const char* ldapDbusService = "xyz.openbmc_project.Ldap.Config"; 456973a582SRatan Gupta constexpr const char* ldapConfigInterface = 466973a582SRatan Gupta "xyz.openbmc_project.User.Ldap.Config"; 476973a582SRatan Gupta constexpr const char* ldapCreateInterface = 486973a582SRatan Gupta "xyz.openbmc_project.User.Ldap.Create"; 496973a582SRatan Gupta constexpr const char* ldapEnableInterface = "xyz.openbmc_project.Object.Enable"; 5006785244SRatan Gupta constexpr const char* ldapPrivMapperInterface = 5106785244SRatan Gupta "xyz.openbmc_project.User.PrivilegeMapper"; 526973a582SRatan Gupta 5354fc587aSNagaraju Goruganti struct LDAPRoleMapData 5454fc587aSNagaraju Goruganti { 5554fc587aSNagaraju Goruganti std::string groupName; 5654fc587aSNagaraju Goruganti std::string privilege; 5754fc587aSNagaraju Goruganti }; 5854fc587aSNagaraju Goruganti 596973a582SRatan Gupta struct LDAPConfigData 606973a582SRatan Gupta { 6147f2934cSEd Tanous std::string uri; 6247f2934cSEd Tanous std::string bindDN; 6347f2934cSEd Tanous std::string baseDN; 6447f2934cSEd Tanous std::string searchScope; 6547f2934cSEd Tanous std::string serverType; 666973a582SRatan Gupta bool serviceEnabled = false; 6747f2934cSEd Tanous std::string userNameAttribute; 6847f2934cSEd Tanous std::string groupAttribute; 6954fc587aSNagaraju Goruganti std::vector<std::pair<std::string, LDAPRoleMapData>> groupRoleList; 706973a582SRatan Gupta }; 716973a582SRatan Gupta 7254fc587aSNagaraju Goruganti inline std::string getRoleIdFromPrivilege(std::string_view role) 7384e12cb7SAppaRao Puli { 7484e12cb7SAppaRao Puli if (role == "priv-admin") 7584e12cb7SAppaRao Puli { 7684e12cb7SAppaRao Puli return "Administrator"; 7784e12cb7SAppaRao Puli } 783174e4dfSEd Tanous if (role == "priv-user") 7984e12cb7SAppaRao Puli { 80c80fee55SAppaRao Puli return "ReadOnly"; 8184e12cb7SAppaRao Puli } 823174e4dfSEd Tanous if (role == "priv-operator") 8384e12cb7SAppaRao Puli { 8484e12cb7SAppaRao Puli return "Operator"; 8584e12cb7SAppaRao Puli } 8684e12cb7SAppaRao Puli return ""; 8784e12cb7SAppaRao Puli } 8854fc587aSNagaraju Goruganti inline std::string getPrivilegeFromRoleId(std::string_view role) 8984e12cb7SAppaRao Puli { 9084e12cb7SAppaRao Puli if (role == "Administrator") 9184e12cb7SAppaRao Puli { 9284e12cb7SAppaRao Puli return "priv-admin"; 9384e12cb7SAppaRao Puli } 943174e4dfSEd Tanous if (role == "ReadOnly") 9584e12cb7SAppaRao Puli { 9684e12cb7SAppaRao Puli return "priv-user"; 9784e12cb7SAppaRao Puli } 983174e4dfSEd Tanous if (role == "Operator") 9984e12cb7SAppaRao Puli { 10084e12cb7SAppaRao Puli return "priv-operator"; 10184e12cb7SAppaRao Puli } 10284e12cb7SAppaRao Puli return ""; 10384e12cb7SAppaRao Puli } 104b9b2e0b2SEd Tanous 105c7229815SAbhishek Patel /** 106c7229815SAbhishek Patel * @brief Maps user group names retrieved from D-Bus object to 107c7229815SAbhishek Patel * Account Types. 108c7229815SAbhishek Patel * 109c7229815SAbhishek Patel * @param[in] userGroups List of User groups 110c7229815SAbhishek Patel * @param[out] res AccountTypes populated 111c7229815SAbhishek Patel * 112c7229815SAbhishek Patel * @return true in case of success, false if UserGroups contains 113c7229815SAbhishek Patel * invalid group name(s). 114c7229815SAbhishek Patel */ 115c7229815SAbhishek Patel inline bool translateUserGroup(const std::vector<std::string>& userGroups, 116c7229815SAbhishek Patel crow::Response& res) 117c7229815SAbhishek Patel { 118c7229815SAbhishek Patel std::vector<std::string> accountTypes; 119c7229815SAbhishek Patel for (const auto& userGroup : userGroups) 120c7229815SAbhishek Patel { 121c7229815SAbhishek Patel if (userGroup == "redfish") 122c7229815SAbhishek Patel { 123c7229815SAbhishek Patel accountTypes.emplace_back("Redfish"); 124c7229815SAbhishek Patel accountTypes.emplace_back("WebUI"); 125c7229815SAbhishek Patel } 126c7229815SAbhishek Patel else if (userGroup == "ipmi") 127c7229815SAbhishek Patel { 128c7229815SAbhishek Patel accountTypes.emplace_back("IPMI"); 129c7229815SAbhishek Patel } 130c7229815SAbhishek Patel else if (userGroup == "ssh") 131c7229815SAbhishek Patel { 132c7229815SAbhishek Patel accountTypes.emplace_back("ManagerConsole"); 133c7229815SAbhishek Patel } 1343e72c202SNinad Palsule else if (userGroup == "hostconsole") 1353e72c202SNinad Palsule { 1363e72c202SNinad Palsule // The hostconsole group controls who can access the host console 1373e72c202SNinad Palsule // port via ssh and websocket. 1383e72c202SNinad Palsule accountTypes.emplace_back("HostConsole"); 1393e72c202SNinad Palsule } 140c7229815SAbhishek Patel else if (userGroup == "web") 141c7229815SAbhishek Patel { 142c7229815SAbhishek Patel // 'web' is one of the valid groups in the UserGroups property of 143c7229815SAbhishek Patel // the user account in the D-Bus object. This group is currently not 144c7229815SAbhishek Patel // doing anything, and is considered to be equivalent to 'redfish'. 145c7229815SAbhishek Patel // 'redfish' user group is mapped to 'Redfish'and 'WebUI' 146c7229815SAbhishek Patel // AccountTypes, so do nothing here... 147c7229815SAbhishek Patel } 148c7229815SAbhishek Patel else 149c7229815SAbhishek Patel { 1508ece0e45SEd Tanous // Invalid user group name. Caller throws an exception. 151c7229815SAbhishek Patel return false; 152c7229815SAbhishek Patel } 153c7229815SAbhishek Patel } 154c7229815SAbhishek Patel 155c7229815SAbhishek Patel res.jsonValue["AccountTypes"] = std::move(accountTypes); 156c7229815SAbhishek Patel return true; 157c7229815SAbhishek Patel } 158c7229815SAbhishek Patel 15958345856SAbhishek Patel /** 16058345856SAbhishek Patel * @brief Builds User Groups from the Account Types 16158345856SAbhishek Patel * 16258345856SAbhishek Patel * @param[in] asyncResp Async Response 16358345856SAbhishek Patel * @param[in] accountTypes List of Account Types 16458345856SAbhishek Patel * @param[out] userGroups List of User Groups mapped from Account Types 16558345856SAbhishek Patel * 16658345856SAbhishek Patel * @return true if Account Types mapped to User Groups, false otherwise. 16758345856SAbhishek Patel */ 168bd79bce8SPatrick Williams inline bool getUserGroupFromAccountType( 169bd79bce8SPatrick Williams crow::Response& res, const std::vector<std::string>& accountTypes, 17058345856SAbhishek Patel std::vector<std::string>& userGroups) 17158345856SAbhishek Patel { 17258345856SAbhishek Patel // Need both Redfish and WebUI Account Types to map to 'redfish' User Group 17358345856SAbhishek Patel bool redfishType = false; 17458345856SAbhishek Patel bool webUIType = false; 17558345856SAbhishek Patel 17658345856SAbhishek Patel for (const auto& accountType : accountTypes) 17758345856SAbhishek Patel { 17858345856SAbhishek Patel if (accountType == "Redfish") 17958345856SAbhishek Patel { 18058345856SAbhishek Patel redfishType = true; 18158345856SAbhishek Patel } 18258345856SAbhishek Patel else if (accountType == "WebUI") 18358345856SAbhishek Patel { 18458345856SAbhishek Patel webUIType = true; 18558345856SAbhishek Patel } 18658345856SAbhishek Patel else if (accountType == "IPMI") 18758345856SAbhishek Patel { 18858345856SAbhishek Patel userGroups.emplace_back("ipmi"); 18958345856SAbhishek Patel } 19058345856SAbhishek Patel else if (accountType == "HostConsole") 19158345856SAbhishek Patel { 19258345856SAbhishek Patel userGroups.emplace_back("hostconsole"); 19358345856SAbhishek Patel } 19458345856SAbhishek Patel else if (accountType == "ManagerConsole") 19558345856SAbhishek Patel { 19658345856SAbhishek Patel userGroups.emplace_back("ssh"); 19758345856SAbhishek Patel } 19858345856SAbhishek Patel else 19958345856SAbhishek Patel { 20058345856SAbhishek Patel // Invalid Account Type 20158345856SAbhishek Patel messages::propertyValueNotInList(res, "AccountTypes", accountType); 20258345856SAbhishek Patel return false; 20358345856SAbhishek Patel } 20458345856SAbhishek Patel } 20558345856SAbhishek Patel 20658345856SAbhishek Patel // Both Redfish and WebUI Account Types are needed to PATCH 20758345856SAbhishek Patel if (redfishType ^ webUIType) 20858345856SAbhishek Patel { 20962598e31SEd Tanous BMCWEB_LOG_ERROR( 21062598e31SEd Tanous "Missing Redfish or WebUI Account Type to set redfish User Group"); 21158345856SAbhishek Patel messages::strictAccountTypes(res, "AccountTypes"); 21258345856SAbhishek Patel return false; 21358345856SAbhishek Patel } 21458345856SAbhishek Patel 21558345856SAbhishek Patel if (redfishType && webUIType) 21658345856SAbhishek Patel { 21758345856SAbhishek Patel userGroups.emplace_back("redfish"); 21858345856SAbhishek Patel } 21958345856SAbhishek Patel 22058345856SAbhishek Patel return true; 22158345856SAbhishek Patel } 22258345856SAbhishek Patel 22358345856SAbhishek Patel /** 22458345856SAbhishek Patel * @brief Sets UserGroups property of the user based on the Account Types 22558345856SAbhishek Patel * 22658345856SAbhishek Patel * @param[in] accountTypes List of User Account Types 22758345856SAbhishek Patel * @param[in] asyncResp Async Response 22858345856SAbhishek Patel * @param[in] dbusObjectPath D-Bus Object Path 22958345856SAbhishek Patel * @param[in] userSelf true if User is updating OWN Account Types 23058345856SAbhishek Patel */ 23158345856SAbhishek Patel inline void 23258345856SAbhishek Patel patchAccountTypes(const std::vector<std::string>& accountTypes, 23358345856SAbhishek Patel const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 23458345856SAbhishek Patel const std::string& dbusObjectPath, bool userSelf) 23558345856SAbhishek Patel { 23658345856SAbhishek Patel // Check if User is disabling own Redfish Account Type 23758345856SAbhishek Patel if (userSelf && 23858345856SAbhishek Patel (accountTypes.cend() == 23958345856SAbhishek Patel std::find(accountTypes.cbegin(), accountTypes.cend(), "Redfish"))) 24058345856SAbhishek Patel { 24162598e31SEd Tanous BMCWEB_LOG_ERROR( 24262598e31SEd Tanous "User disabling OWN Redfish Account Type is not allowed"); 24358345856SAbhishek Patel messages::strictAccountTypes(asyncResp->res, "AccountTypes"); 24458345856SAbhishek Patel return; 24558345856SAbhishek Patel } 24658345856SAbhishek Patel 24758345856SAbhishek Patel std::vector<std::string> updatedUserGroups; 24858345856SAbhishek Patel if (!getUserGroupFromAccountType(asyncResp->res, accountTypes, 24958345856SAbhishek Patel updatedUserGroups)) 25058345856SAbhishek Patel { 25158345856SAbhishek Patel // Problem in mapping Account Types to User Groups, Error already 25258345856SAbhishek Patel // logged. 25358345856SAbhishek Patel return; 25458345856SAbhishek Patel } 255e93abac6SGinu George setDbusProperty(asyncResp, "AccountTypes", 256e93abac6SGinu George "xyz.openbmc_project.User.Manager", dbusObjectPath, 257e93abac6SGinu George "xyz.openbmc_project.User.Attributes", "UserGroups", 258e93abac6SGinu George updatedUserGroups); 25958345856SAbhishek Patel } 26058345856SAbhishek Patel 2618d1b46d7Szhanghch05 inline void userErrorMessageHandler( 2628d1b46d7Szhanghch05 const sd_bus_error* e, const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2638d1b46d7Szhanghch05 const std::string& newUser, const std::string& username) 26466b5ca76Sjayaprakash Mutyala { 26566b5ca76Sjayaprakash Mutyala if (e == nullptr) 26666b5ca76Sjayaprakash Mutyala { 26766b5ca76Sjayaprakash Mutyala messages::internalError(asyncResp->res); 26866b5ca76Sjayaprakash Mutyala return; 26966b5ca76Sjayaprakash Mutyala } 27066b5ca76Sjayaprakash Mutyala 271055806b3SManojkiran Eda const char* errorMessage = e->name; 27266b5ca76Sjayaprakash Mutyala if (strcmp(errorMessage, 27366b5ca76Sjayaprakash Mutyala "xyz.openbmc_project.User.Common.Error.UserNameExists") == 0) 27466b5ca76Sjayaprakash Mutyala { 275d8a5d5d8SJiaqing Zhao messages::resourceAlreadyExists(asyncResp->res, "ManagerAccount", 27666b5ca76Sjayaprakash Mutyala "UserName", newUser); 27766b5ca76Sjayaprakash Mutyala } 27866b5ca76Sjayaprakash Mutyala else if (strcmp(errorMessage, "xyz.openbmc_project.User.Common.Error." 27966b5ca76Sjayaprakash Mutyala "UserNameDoesNotExist") == 0) 28066b5ca76Sjayaprakash Mutyala { 281d8a5d5d8SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "ManagerAccount", username); 28266b5ca76Sjayaprakash Mutyala } 283d4d25793SEd Tanous else if ((strcmp(errorMessage, 284d4d25793SEd Tanous "xyz.openbmc_project.Common.Error.InvalidArgument") == 285d4d25793SEd Tanous 0) || 2860fda0f12SGeorge Liu (strcmp( 2870fda0f12SGeorge Liu errorMessage, 2880fda0f12SGeorge Liu "xyz.openbmc_project.User.Common.Error.UserNameGroupFail") == 2890fda0f12SGeorge Liu 0)) 29066b5ca76Sjayaprakash Mutyala { 29166b5ca76Sjayaprakash Mutyala messages::propertyValueFormatError(asyncResp->res, newUser, "UserName"); 29266b5ca76Sjayaprakash Mutyala } 29366b5ca76Sjayaprakash Mutyala else if (strcmp(errorMessage, 29466b5ca76Sjayaprakash Mutyala "xyz.openbmc_project.User.Common.Error.NoResource") == 0) 29566b5ca76Sjayaprakash Mutyala { 29666b5ca76Sjayaprakash Mutyala messages::createLimitReachedForResource(asyncResp->res); 29766b5ca76Sjayaprakash Mutyala } 29866b5ca76Sjayaprakash Mutyala else 29966b5ca76Sjayaprakash Mutyala { 300b8ad583fSGunnar Mills BMCWEB_LOG_ERROR("DBUS response error {}", errorMessage); 30166b5ca76Sjayaprakash Mutyala messages::internalError(asyncResp->res); 30266b5ca76Sjayaprakash Mutyala } 30366b5ca76Sjayaprakash Mutyala } 30466b5ca76Sjayaprakash Mutyala 30581ce609eSEd Tanous inline void parseLDAPConfigData(nlohmann::json& jsonResponse, 306ab828d7cSRatan Gupta const LDAPConfigData& confData, 307ab828d7cSRatan Gupta const std::string& ldapType) 3086973a582SRatan Gupta { 30949cc263fSEd Tanous nlohmann::json::object_t ldap; 3101476687dSEd Tanous ldap["ServiceEnabled"] = confData.serviceEnabled; 31149cc263fSEd Tanous nlohmann::json::array_t serviceAddresses; 31249cc263fSEd Tanous serviceAddresses.emplace_back(confData.uri); 31349cc263fSEd Tanous ldap["ServiceAddresses"] = std::move(serviceAddresses); 31449cc263fSEd Tanous 31549cc263fSEd Tanous nlohmann::json::object_t authentication; 31649cc263fSEd Tanous authentication["AuthenticationType"] = 3170ec8b83dSEd Tanous account_service::AuthenticationTypes::UsernameAndPassword; 31849cc263fSEd Tanous authentication["Username"] = confData.bindDN; 31949cc263fSEd Tanous authentication["Password"] = nullptr; 32049cc263fSEd Tanous ldap["Authentication"] = std::move(authentication); 3211476687dSEd Tanous 32249cc263fSEd Tanous nlohmann::json::object_t ldapService; 32349cc263fSEd Tanous nlohmann::json::object_t searchSettings; 32449cc263fSEd Tanous nlohmann::json::array_t baseDistinguishedNames; 32549cc263fSEd Tanous baseDistinguishedNames.emplace_back(confData.baseDN); 3261476687dSEd Tanous 32749cc263fSEd Tanous searchSettings["BaseDistinguishedNames"] = 32849cc263fSEd Tanous std::move(baseDistinguishedNames); 32949cc263fSEd Tanous searchSettings["UsernameAttribute"] = confData.userNameAttribute; 33049cc263fSEd Tanous searchSettings["GroupsAttribute"] = confData.groupAttribute; 33149cc263fSEd Tanous ldapService["SearchSettings"] = std::move(searchSettings); 33249cc263fSEd Tanous ldap["LDAPService"] = std::move(ldapService); 33349cc263fSEd Tanous 33449cc263fSEd Tanous nlohmann::json::array_t roleMapArray; 3359eb808c1SEd Tanous for (const auto& obj : confData.groupRoleList) 33654fc587aSNagaraju Goruganti { 33762598e31SEd Tanous BMCWEB_LOG_DEBUG("Pushing the data groupName={}", obj.second.groupName); 338613dabeaSEd Tanous 339613dabeaSEd Tanous nlohmann::json::object_t remoteGroup; 340613dabeaSEd Tanous remoteGroup["RemoteGroup"] = obj.second.groupName; 341329f0348SJorge Cisneros remoteGroup["LocalRole"] = getRoleIdFromPrivilege(obj.second.privilege); 342329f0348SJorge Cisneros roleMapArray.emplace_back(std::move(remoteGroup)); 34354fc587aSNagaraju Goruganti } 34449cc263fSEd Tanous 34549cc263fSEd Tanous ldap["RemoteRoleMapping"] = std::move(roleMapArray); 34649cc263fSEd Tanous 34749cc263fSEd Tanous jsonResponse[ldapType].update(ldap); 3486973a582SRatan Gupta } 3496973a582SRatan Gupta 3506973a582SRatan Gupta /** 35106785244SRatan Gupta * @brief validates given JSON input and then calls appropriate method to 35206785244SRatan Gupta * create, to delete or to set Rolemapping object based on the given input. 35306785244SRatan Gupta * 35406785244SRatan Gupta */ 35523a21a1cSEd Tanous inline void handleRoleMapPatch( 3568d1b46d7Szhanghch05 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 35706785244SRatan Gupta const std::vector<std::pair<std::string, LDAPRoleMapData>>& roleMapObjData, 358c1019828SEd Tanous const std::string& serverType, 359c1019828SEd Tanous std::vector<std::variant<nlohmann::json::object_t, std::nullptr_t>>& input) 36006785244SRatan Gupta { 36106785244SRatan Gupta for (size_t index = 0; index < input.size(); index++) 36206785244SRatan Gupta { 363c1019828SEd Tanous std::variant<nlohmann::json::object_t, std::nullptr_t>& thisJson = 364c1019828SEd Tanous input[index]; 365c1019828SEd Tanous nlohmann::json::object_t* obj = 366c1019828SEd Tanous std::get_if<nlohmann::json::object_t>(&thisJson); 367c1019828SEd Tanous if (obj == nullptr) 36806785244SRatan Gupta { 36906785244SRatan Gupta // delete the existing object 37006785244SRatan Gupta if (index < roleMapObjData.size()) 37106785244SRatan Gupta { 37206785244SRatan Gupta crow::connections::systemBus->async_method_call( 37306785244SRatan Gupta [asyncResp, roleMapObjData, serverType, 3745e7e2dc5SEd Tanous index](const boost::system::error_code& ec) { 37506785244SRatan Gupta if (ec) 37606785244SRatan Gupta { 37762598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error: {}", ec); 37806785244SRatan Gupta messages::internalError(asyncResp->res); 37906785244SRatan Gupta return; 38006785244SRatan Gupta } 381bd79bce8SPatrick Williams asyncResp->res 382bd79bce8SPatrick Williams .jsonValue[serverType]["RemoteRoleMapping"][index] = 383bd79bce8SPatrick Williams nullptr; 38406785244SRatan Gupta }, 38506785244SRatan Gupta ldapDbusService, roleMapObjData[index].first, 38606785244SRatan Gupta "xyz.openbmc_project.Object.Delete", "Delete"); 38706785244SRatan Gupta } 38806785244SRatan Gupta else 38906785244SRatan Gupta { 39062598e31SEd Tanous BMCWEB_LOG_ERROR("Can't delete the object"); 391bd79bce8SPatrick Williams messages::propertyValueTypeError( 392bd79bce8SPatrick Williams asyncResp->res, "null", 393bd79bce8SPatrick Williams "RemoteRoleMapping/" + std::to_string(index)); 39406785244SRatan Gupta return; 39506785244SRatan Gupta } 39606785244SRatan Gupta } 397c1019828SEd Tanous else if (obj->empty()) 39806785244SRatan Gupta { 39906785244SRatan Gupta // Don't do anything for the empty objects,parse next json 40006785244SRatan Gupta // eg {"RemoteRoleMapping",[{}]} 40106785244SRatan Gupta } 40206785244SRatan Gupta else 40306785244SRatan Gupta { 40406785244SRatan Gupta // update/create the object 40506785244SRatan Gupta std::optional<std::string> remoteGroup; 40606785244SRatan Gupta std::optional<std::string> localRole; 40706785244SRatan Gupta 408afc474aeSMyung Bae if (!json_util::readJsonObject( // 409afc474aeSMyung Bae *obj, asyncResp->res, // 410afc474aeSMyung Bae "LocalRole", localRole, // 411afc474aeSMyung Bae "RemoteGroup", remoteGroup // 412afc474aeSMyung Bae )) 41306785244SRatan Gupta { 41406785244SRatan Gupta continue; 41506785244SRatan Gupta } 41606785244SRatan Gupta 41706785244SRatan Gupta // Update existing RoleMapping Object 41806785244SRatan Gupta if (index < roleMapObjData.size()) 41906785244SRatan Gupta { 42062598e31SEd Tanous BMCWEB_LOG_DEBUG("Update Role Map Object"); 42106785244SRatan Gupta // If "RemoteGroup" info is provided 42206785244SRatan Gupta if (remoteGroup) 42306785244SRatan Gupta { 424d02aad39SEd Tanous setDbusProperty( 425e93abac6SGinu George asyncResp, 426d02aad39SEd Tanous std::format("RemoteRoleMapping/{}/RemoteGroup", index), 427e93abac6SGinu George ldapDbusService, roleMapObjData[index].first, 428e93abac6SGinu George "xyz.openbmc_project.User.PrivilegeMapperEntry", 429e93abac6SGinu George "GroupName", *remoteGroup); 43006785244SRatan Gupta } 43106785244SRatan Gupta 43206785244SRatan Gupta // If "LocalRole" info is provided 43306785244SRatan Gupta if (localRole) 43406785244SRatan Gupta { 4356d0b80beSRavi Teja std::string priv = getPrivilegeFromRoleId(*localRole); 4366d0b80beSRavi Teja if (priv.empty()) 4376d0b80beSRavi Teja { 4386d0b80beSRavi Teja messages::propertyValueNotInList( 4396d0b80beSRavi Teja asyncResp->res, *localRole, 4406d0b80beSRavi Teja std::format("RemoteRoleMapping/{}/LocalRole", 4416d0b80beSRavi Teja index)); 4426d0b80beSRavi Teja return; 4436d0b80beSRavi Teja } 444d02aad39SEd Tanous setDbusProperty( 445e93abac6SGinu George asyncResp, 446d02aad39SEd Tanous std::format("RemoteRoleMapping/{}/LocalRole", index), 447e93abac6SGinu George ldapDbusService, roleMapObjData[index].first, 448e93abac6SGinu George "xyz.openbmc_project.User.PrivilegeMapperEntry", 4496d0b80beSRavi Teja "Privilege", priv); 45006785244SRatan Gupta } 45106785244SRatan Gupta } 45206785244SRatan Gupta // Create a new RoleMapping Object. 45306785244SRatan Gupta else 45406785244SRatan Gupta { 45562598e31SEd Tanous BMCWEB_LOG_DEBUG( 45662598e31SEd Tanous "setRoleMappingProperties: Creating new Object"); 457bd79bce8SPatrick Williams std::string pathString = 458bd79bce8SPatrick Williams "RemoteRoleMapping/" + std::to_string(index); 45906785244SRatan Gupta 46006785244SRatan Gupta if (!localRole) 46106785244SRatan Gupta { 46206785244SRatan Gupta messages::propertyMissing(asyncResp->res, 46306785244SRatan Gupta pathString + "/LocalRole"); 46406785244SRatan Gupta continue; 46506785244SRatan Gupta } 46606785244SRatan Gupta if (!remoteGroup) 46706785244SRatan Gupta { 46806785244SRatan Gupta messages::propertyMissing(asyncResp->res, 46906785244SRatan Gupta pathString + "/RemoteGroup"); 47006785244SRatan Gupta continue; 47106785244SRatan Gupta } 47206785244SRatan Gupta 47306785244SRatan Gupta std::string dbusObjectPath; 47406785244SRatan Gupta if (serverType == "ActiveDirectory") 47506785244SRatan Gupta { 4762c70f800SEd Tanous dbusObjectPath = adConfigObject; 47706785244SRatan Gupta } 47806785244SRatan Gupta else if (serverType == "LDAP") 47906785244SRatan Gupta { 48023a21a1cSEd Tanous dbusObjectPath = ldapConfigObjectName; 48106785244SRatan Gupta } 48206785244SRatan Gupta 48362598e31SEd Tanous BMCWEB_LOG_DEBUG("Remote Group={},LocalRole={}", *remoteGroup, 48462598e31SEd Tanous *localRole); 48506785244SRatan Gupta 48606785244SRatan Gupta crow::connections::systemBus->async_method_call( 487271584abSEd Tanous [asyncResp, serverType, localRole, 4885e7e2dc5SEd Tanous remoteGroup](const boost::system::error_code& ec) { 48906785244SRatan Gupta if (ec) 49006785244SRatan Gupta { 49162598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error: {}", ec); 49206785244SRatan Gupta messages::internalError(asyncResp->res); 49306785244SRatan Gupta return; 49406785244SRatan Gupta } 49506785244SRatan Gupta nlohmann::json& remoteRoleJson = 49606785244SRatan Gupta asyncResp->res 49706785244SRatan Gupta .jsonValue[serverType]["RemoteRoleMapping"]; 4981476687dSEd Tanous nlohmann::json::object_t roleMapEntry; 4991476687dSEd Tanous roleMapEntry["LocalRole"] = *localRole; 5001476687dSEd Tanous roleMapEntry["RemoteGroup"] = *remoteGroup; 501b2ba3072SPatrick Williams remoteRoleJson.emplace_back(std::move(roleMapEntry)); 50206785244SRatan Gupta }, 50306785244SRatan Gupta ldapDbusService, dbusObjectPath, ldapPrivMapperInterface, 5043174e4dfSEd Tanous "Create", *remoteGroup, 50506785244SRatan Gupta getPrivilegeFromRoleId(std::move(*localRole))); 50606785244SRatan Gupta } 50706785244SRatan Gupta } 50806785244SRatan Gupta } 50906785244SRatan Gupta } 51006785244SRatan Gupta 51106785244SRatan Gupta /** 5126973a582SRatan Gupta * Function that retrieves all properties for LDAP config object 5136973a582SRatan Gupta * into JSON 5146973a582SRatan Gupta */ 5156973a582SRatan Gupta template <typename CallbackFunc> 516bd79bce8SPatrick Williams inline void 517bd79bce8SPatrick Williams getLDAPConfigData(const std::string& ldapType, CallbackFunc&& callback) 5186973a582SRatan Gupta { 5192b73119cSGeorge Liu constexpr std::array<std::string_view, 2> interfaces = { 5202b73119cSGeorge Liu ldapEnableInterface, ldapConfigInterface}; 52154fc587aSNagaraju Goruganti 5222b73119cSGeorge Liu dbus::utility::getDbusObject( 5232b73119cSGeorge Liu ldapConfigObjectName, interfaces, 5248cb2c024SEd Tanous [callback = std::forward<CallbackFunc>(callback), 525c1019828SEd Tanous ldapType](const boost::system::error_code& ec, 526c1019828SEd Tanous const dbus::utility::MapperGetObject& resp) mutable { 52754fc587aSNagaraju Goruganti if (ec || resp.empty()) 52854fc587aSNagaraju Goruganti { 529bf2ddedeSCarson Labrado BMCWEB_LOG_WARNING( 530bd79bce8SPatrick Williams "DBUS response error during getting of service name: {}", 531bd79bce8SPatrick Williams ec); 53223a21a1cSEd Tanous LDAPConfigData empty{}; 53323a21a1cSEd Tanous callback(false, empty, ldapType); 53454fc587aSNagaraju Goruganti return; 53554fc587aSNagaraju Goruganti } 53654fc587aSNagaraju Goruganti std::string service = resp.begin()->first; 5375eb468daSGeorge Liu sdbusplus::message::object_path path(ldapRootObject); 5385eb468daSGeorge Liu dbus::utility::getManagedObjects( 5395eb468daSGeorge Liu service, path, 540bd79bce8SPatrick Williams [callback, ldapType](const boost::system::error_code& ec2, 541bd79bce8SPatrick Williams const dbus::utility::ManagedObjectType& 542bd79bce8SPatrick Williams ldapObjects) mutable { 5436973a582SRatan Gupta LDAPConfigData confData{}; 5448b24275dSEd Tanous if (ec2) 5456973a582SRatan Gupta { 546ab828d7cSRatan Gupta callback(false, confData, ldapType); 547bf2ddedeSCarson Labrado BMCWEB_LOG_WARNING("D-Bus responses error: {}", ec2); 5486973a582SRatan Gupta return; 5496973a582SRatan Gupta } 550ab828d7cSRatan Gupta 551ab828d7cSRatan Gupta std::string ldapDbusType; 55254fc587aSNagaraju Goruganti std::string searchString; 55354fc587aSNagaraju Goruganti 554ab828d7cSRatan Gupta if (ldapType == "LDAP") 555ab828d7cSRatan Gupta { 5560fda0f12SGeorge Liu ldapDbusType = 5570fda0f12SGeorge Liu "xyz.openbmc_project.User.Ldap.Config.Type.OpenLdap"; 55854fc587aSNagaraju Goruganti searchString = "openldap"; 559ab828d7cSRatan Gupta } 560ab828d7cSRatan Gupta else if (ldapType == "ActiveDirectory") 561ab828d7cSRatan Gupta { 56254fc587aSNagaraju Goruganti ldapDbusType = 5630fda0f12SGeorge Liu "xyz.openbmc_project.User.Ldap.Config.Type.ActiveDirectory"; 56454fc587aSNagaraju Goruganti searchString = "active_directory"; 565ab828d7cSRatan Gupta } 566ab828d7cSRatan Gupta else 567ab828d7cSRatan Gupta { 568bd79bce8SPatrick Williams BMCWEB_LOG_ERROR( 569bd79bce8SPatrick Williams "Can't get the DbusType for the given type={}", 57062598e31SEd Tanous ldapType); 571ab828d7cSRatan Gupta callback(false, confData, ldapType); 572ab828d7cSRatan Gupta return; 573ab828d7cSRatan Gupta } 574ab828d7cSRatan Gupta 575ab828d7cSRatan Gupta std::string ldapEnableInterfaceStr = ldapEnableInterface; 576ab828d7cSRatan Gupta std::string ldapConfigInterfaceStr = ldapConfigInterface; 577ab828d7cSRatan Gupta 5786973a582SRatan Gupta for (const auto& object : ldapObjects) 5796973a582SRatan Gupta { 58054fc587aSNagaraju Goruganti // let's find the object whose ldap type is equal to the 58154fc587aSNagaraju Goruganti // given type 582bd79bce8SPatrick Williams if (object.first.str.find(searchString) == 583bd79bce8SPatrick Williams std::string::npos) 5846973a582SRatan Gupta { 585ab828d7cSRatan Gupta continue; 586ab828d7cSRatan Gupta } 587ab828d7cSRatan Gupta 5886973a582SRatan Gupta for (const auto& interface : object.second) 5896973a582SRatan Gupta { 5906973a582SRatan Gupta if (interface.first == ldapEnableInterfaceStr) 5916973a582SRatan Gupta { 5926973a582SRatan Gupta // rest of the properties are string. 5936973a582SRatan Gupta for (const auto& property : interface.second) 5946973a582SRatan Gupta { 5956973a582SRatan Gupta if (property.first == "Enabled") 5966973a582SRatan Gupta { 5976973a582SRatan Gupta const bool* value = 5986973a582SRatan Gupta std::get_if<bool>(&property.second); 5996973a582SRatan Gupta if (value == nullptr) 6006973a582SRatan Gupta { 6016973a582SRatan Gupta continue; 6026973a582SRatan Gupta } 6036973a582SRatan Gupta confData.serviceEnabled = *value; 6046973a582SRatan Gupta break; 6056973a582SRatan Gupta } 6066973a582SRatan Gupta } 6076973a582SRatan Gupta } 6086973a582SRatan Gupta else if (interface.first == ldapConfigInterfaceStr) 6096973a582SRatan Gupta { 6106973a582SRatan Gupta for (const auto& property : interface.second) 6116973a582SRatan Gupta { 612271584abSEd Tanous const std::string* strValue = 613bd79bce8SPatrick Williams std::get_if<std::string>( 614bd79bce8SPatrick Williams &property.second); 615271584abSEd Tanous if (strValue == nullptr) 6166973a582SRatan Gupta { 6176973a582SRatan Gupta continue; 6186973a582SRatan Gupta } 6196973a582SRatan Gupta if (property.first == "LDAPServerURI") 6206973a582SRatan Gupta { 621271584abSEd Tanous confData.uri = *strValue; 6226973a582SRatan Gupta } 6236973a582SRatan Gupta else if (property.first == "LDAPBindDN") 6246973a582SRatan Gupta { 625271584abSEd Tanous confData.bindDN = *strValue; 6266973a582SRatan Gupta } 6276973a582SRatan Gupta else if (property.first == "LDAPBaseDN") 6286973a582SRatan Gupta { 629271584abSEd Tanous confData.baseDN = *strValue; 6306973a582SRatan Gupta } 631bd79bce8SPatrick Williams else if (property.first == 632bd79bce8SPatrick Williams "LDAPSearchScope") 6336973a582SRatan Gupta { 634271584abSEd Tanous confData.searchScope = *strValue; 6356973a582SRatan Gupta } 636bd79bce8SPatrick Williams else if (property.first == 637bd79bce8SPatrick Williams "GroupNameAttribute") 6386973a582SRatan Gupta { 639271584abSEd Tanous confData.groupAttribute = *strValue; 6406973a582SRatan Gupta } 641bd79bce8SPatrick Williams else if (property.first == 642bd79bce8SPatrick Williams "UserNameAttribute") 6436973a582SRatan Gupta { 644271584abSEd Tanous confData.userNameAttribute = *strValue; 6456973a582SRatan Gupta } 64654fc587aSNagaraju Goruganti else if (property.first == "LDAPType") 647ab828d7cSRatan Gupta { 648271584abSEd Tanous confData.serverType = *strValue; 64954fc587aSNagaraju Goruganti } 65054fc587aSNagaraju Goruganti } 65154fc587aSNagaraju Goruganti } 652bd79bce8SPatrick Williams else if ( 653bd79bce8SPatrick Williams interface.first == 6540fda0f12SGeorge Liu "xyz.openbmc_project.User.PrivilegeMapperEntry") 65554fc587aSNagaraju Goruganti { 65654fc587aSNagaraju Goruganti LDAPRoleMapData roleMapData{}; 65754fc587aSNagaraju Goruganti for (const auto& property : interface.second) 65854fc587aSNagaraju Goruganti { 659271584abSEd Tanous const std::string* strValue = 660bd79bce8SPatrick Williams std::get_if<std::string>( 661bd79bce8SPatrick Williams &property.second); 66254fc587aSNagaraju Goruganti 663271584abSEd Tanous if (strValue == nullptr) 66454fc587aSNagaraju Goruganti { 66554fc587aSNagaraju Goruganti continue; 66654fc587aSNagaraju Goruganti } 66754fc587aSNagaraju Goruganti 66854fc587aSNagaraju Goruganti if (property.first == "GroupName") 66954fc587aSNagaraju Goruganti { 670271584abSEd Tanous roleMapData.groupName = *strValue; 67154fc587aSNagaraju Goruganti } 67254fc587aSNagaraju Goruganti else if (property.first == "Privilege") 67354fc587aSNagaraju Goruganti { 674271584abSEd Tanous roleMapData.privilege = *strValue; 67554fc587aSNagaraju Goruganti } 67654fc587aSNagaraju Goruganti } 67754fc587aSNagaraju Goruganti 678bd79bce8SPatrick Williams confData.groupRoleList.emplace_back( 679bd79bce8SPatrick Williams object.first.str, roleMapData); 68054fc587aSNagaraju Goruganti } 68154fc587aSNagaraju Goruganti } 68254fc587aSNagaraju Goruganti } 683ab828d7cSRatan Gupta callback(true, confData, ldapType); 6845eb468daSGeorge Liu }); 6852b73119cSGeorge Liu }); 6866973a582SRatan Gupta } 6876973a582SRatan Gupta 6888a07d286SRatan Gupta /** 6898a07d286SRatan Gupta * @brief updates the LDAP server address and updates the 6908a07d286SRatan Gupta json response with the new value. 6918a07d286SRatan Gupta * @param serviceAddressList address to be updated. 6928a07d286SRatan Gupta * @param asyncResp pointer to the JSON response 6938a07d286SRatan Gupta * @param ldapServerElementName Type of LDAP 6948a07d286SRatan Gupta server(openLDAP/ActiveDirectory) 6958a07d286SRatan Gupta */ 6968a07d286SRatan Gupta 6974f48d5f6SEd Tanous inline void handleServiceAddressPatch( 6988a07d286SRatan Gupta const std::vector<std::string>& serviceAddressList, 6998d1b46d7Szhanghch05 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 7008a07d286SRatan Gupta const std::string& ldapServerElementName, 7018a07d286SRatan Gupta const std::string& ldapConfigObject) 7028a07d286SRatan Gupta { 703e93abac6SGinu George setDbusProperty(asyncResp, ldapServerElementName + "/ServiceAddress", 704e93abac6SGinu George ldapDbusService, ldapConfigObject, ldapConfigInterface, 705e93abac6SGinu George "LDAPServerURI", serviceAddressList.front()); 7068a07d286SRatan Gupta } 7078a07d286SRatan Gupta /** 7088a07d286SRatan Gupta * @brief updates the LDAP Bind DN and updates the 7098a07d286SRatan Gupta json response with the new value. 7108a07d286SRatan Gupta * @param username name of the user which needs to be updated. 7118a07d286SRatan Gupta * @param asyncResp pointer to the JSON response 7128a07d286SRatan Gupta * @param ldapServerElementName Type of LDAP 7138a07d286SRatan Gupta server(openLDAP/ActiveDirectory) 7148a07d286SRatan Gupta */ 7158a07d286SRatan Gupta 7164f48d5f6SEd Tanous inline void 7174f48d5f6SEd Tanous handleUserNamePatch(const std::string& username, 7188d1b46d7Szhanghch05 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 7198a07d286SRatan Gupta const std::string& ldapServerElementName, 7208a07d286SRatan Gupta const std::string& ldapConfigObject) 7218a07d286SRatan Gupta { 722e93abac6SGinu George setDbusProperty(asyncResp, 723d02aad39SEd Tanous ldapServerElementName + "/Authentication/Username", 724e93abac6SGinu George ldapDbusService, ldapConfigObject, ldapConfigInterface, 725e93abac6SGinu George "LDAPBindDN", username); 7268a07d286SRatan Gupta } 7278a07d286SRatan Gupta 7288a07d286SRatan Gupta /** 7298a07d286SRatan Gupta * @brief updates the LDAP password 7308a07d286SRatan Gupta * @param password : ldap password which needs to be updated. 7318a07d286SRatan Gupta * @param asyncResp pointer to the JSON response 7328a07d286SRatan Gupta * @param ldapServerElementName Type of LDAP 7338a07d286SRatan Gupta * server(openLDAP/ActiveDirectory) 7348a07d286SRatan Gupta */ 7358a07d286SRatan Gupta 7364f48d5f6SEd Tanous inline void 7374f48d5f6SEd Tanous handlePasswordPatch(const std::string& password, 7388d1b46d7Szhanghch05 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 7398a07d286SRatan Gupta const std::string& ldapServerElementName, 7408a07d286SRatan Gupta const std::string& ldapConfigObject) 7418a07d286SRatan Gupta { 742e93abac6SGinu George setDbusProperty(asyncResp, 743d02aad39SEd Tanous ldapServerElementName + "/Authentication/Password", 744e93abac6SGinu George ldapDbusService, ldapConfigObject, ldapConfigInterface, 745e93abac6SGinu George "LDAPBindDNPassword", password); 7468a07d286SRatan Gupta } 7478a07d286SRatan Gupta 7488a07d286SRatan Gupta /** 7498a07d286SRatan Gupta * @brief updates the LDAP BaseDN and updates the 7508a07d286SRatan Gupta json response with the new value. 7518a07d286SRatan Gupta * @param baseDNList baseDN list which needs to be updated. 7528a07d286SRatan Gupta * @param asyncResp pointer to the JSON response 7538a07d286SRatan Gupta * @param ldapServerElementName Type of LDAP 7548a07d286SRatan Gupta server(openLDAP/ActiveDirectory) 7558a07d286SRatan Gupta */ 7568a07d286SRatan Gupta 7574f48d5f6SEd Tanous inline void 7584f48d5f6SEd Tanous handleBaseDNPatch(const std::vector<std::string>& baseDNList, 7598d1b46d7Szhanghch05 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 7608a07d286SRatan Gupta const std::string& ldapServerElementName, 7618a07d286SRatan Gupta const std::string& ldapConfigObject) 7628a07d286SRatan Gupta { 763e93abac6SGinu George setDbusProperty(asyncResp, 764d02aad39SEd Tanous ldapServerElementName + 765d02aad39SEd Tanous "/LDAPService/SearchSettings/BaseDistinguishedNames", 766e93abac6SGinu George ldapDbusService, ldapConfigObject, ldapConfigInterface, 767e93abac6SGinu George "LDAPBaseDN", baseDNList.front()); 7688a07d286SRatan Gupta } 7698a07d286SRatan Gupta /** 7708a07d286SRatan Gupta * @brief updates the LDAP user name attribute and updates the 7718a07d286SRatan Gupta json response with the new value. 7728a07d286SRatan Gupta * @param userNameAttribute attribute to be updated. 7738a07d286SRatan Gupta * @param asyncResp pointer to the JSON response 7748a07d286SRatan Gupta * @param ldapServerElementName Type of LDAP 7758a07d286SRatan Gupta server(openLDAP/ActiveDirectory) 7768a07d286SRatan Gupta */ 7778a07d286SRatan Gupta 778bd79bce8SPatrick Williams inline void handleUserNameAttrPatch( 779bd79bce8SPatrick Williams const std::string& userNameAttribute, 7808d1b46d7Szhanghch05 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 7818a07d286SRatan Gupta const std::string& ldapServerElementName, 7828a07d286SRatan Gupta const std::string& ldapConfigObject) 7838a07d286SRatan Gupta { 784bd79bce8SPatrick Williams setDbusProperty( 785bd79bce8SPatrick Williams asyncResp, 786bd79bce8SPatrick Williams ldapServerElementName + "LDAPService/SearchSettings/UsernameAttribute", 787e93abac6SGinu George ldapDbusService, ldapConfigObject, ldapConfigInterface, 788e93abac6SGinu George "UserNameAttribute", userNameAttribute); 7898a07d286SRatan Gupta } 7908a07d286SRatan Gupta /** 7918a07d286SRatan Gupta * @brief updates the LDAP group attribute and updates the 7928a07d286SRatan Gupta json response with the new value. 7938a07d286SRatan Gupta * @param groupsAttribute attribute to be updated. 7948a07d286SRatan Gupta * @param asyncResp pointer to the JSON response 7958a07d286SRatan Gupta * @param ldapServerElementName Type of LDAP 7968a07d286SRatan Gupta server(openLDAP/ActiveDirectory) 7978a07d286SRatan Gupta */ 7988a07d286SRatan Gupta 7994f48d5f6SEd Tanous inline void handleGroupNameAttrPatch( 8008d1b46d7Szhanghch05 const std::string& groupsAttribute, 8018d1b46d7Szhanghch05 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 8028a07d286SRatan Gupta const std::string& ldapServerElementName, 8038a07d286SRatan Gupta const std::string& ldapConfigObject) 8048a07d286SRatan Gupta { 805bd79bce8SPatrick Williams setDbusProperty( 806bd79bce8SPatrick Williams asyncResp, 807bd79bce8SPatrick Williams ldapServerElementName + "/LDAPService/SearchSettings/GroupsAttribute", 808e93abac6SGinu George ldapDbusService, ldapConfigObject, ldapConfigInterface, 809e93abac6SGinu George "GroupNameAttribute", groupsAttribute); 8108a07d286SRatan Gupta } 8118a07d286SRatan Gupta /** 8128a07d286SRatan Gupta * @brief updates the LDAP service enable and updates the 8138a07d286SRatan Gupta json response with the new value. 8148a07d286SRatan Gupta * @param input JSON data. 8158a07d286SRatan Gupta * @param asyncResp pointer to the JSON response 8168a07d286SRatan Gupta * @param ldapServerElementName Type of LDAP 8178a07d286SRatan Gupta server(openLDAP/ActiveDirectory) 8188a07d286SRatan Gupta */ 8198a07d286SRatan Gupta 8204f48d5f6SEd Tanous inline void handleServiceEnablePatch( 8216c51eab1SEd Tanous bool serviceEnabled, const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 8228a07d286SRatan Gupta const std::string& ldapServerElementName, 8238a07d286SRatan Gupta const std::string& ldapConfigObject) 8248a07d286SRatan Gupta { 825e93abac6SGinu George setDbusProperty(asyncResp, ldapServerElementName + "/ServiceEnabled", 826e93abac6SGinu George ldapDbusService, ldapConfigObject, ldapEnableInterface, 827e93abac6SGinu George "Enabled", serviceEnabled); 8288a07d286SRatan Gupta } 8298a07d286SRatan Gupta 830c1019828SEd Tanous struct AuthMethods 83178158631SZbigniew Kurzynski { 83278158631SZbigniew Kurzynski std::optional<bool> basicAuth; 83378158631SZbigniew Kurzynski std::optional<bool> cookie; 83478158631SZbigniew Kurzynski std::optional<bool> sessionToken; 83578158631SZbigniew Kurzynski std::optional<bool> xToken; 836501f1e58SZbigniew Kurzynski std::optional<bool> tls; 837c1019828SEd Tanous }; 83878158631SZbigniew Kurzynski 839c1019828SEd Tanous inline void 840c1019828SEd Tanous handleAuthMethodsPatch(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 841c1019828SEd Tanous const AuthMethods& auth) 84278158631SZbigniew Kurzynski { 843c1019828SEd Tanous persistent_data::AuthConfigMethods& authMethodsConfig = 84452cc112dSEd Tanous persistent_data::SessionStore::getInstance().getAuthMethodsConfig(); 84578158631SZbigniew Kurzynski 846c1019828SEd Tanous if (auth.basicAuth) 84778158631SZbigniew Kurzynski { 84825b54dbaSEd Tanous if constexpr (!BMCWEB_BASIC_AUTH) 84925b54dbaSEd Tanous { 850f16f6263SAlan Kuo messages::actionNotSupported( 8510fda0f12SGeorge Liu asyncResp->res, 8520fda0f12SGeorge Liu "Setting BasicAuth when basic-auth feature is disabled"); 853f16f6263SAlan Kuo return; 85425b54dbaSEd Tanous } 85525b54dbaSEd Tanous 856c1019828SEd Tanous authMethodsConfig.basic = *auth.basicAuth; 85778158631SZbigniew Kurzynski } 85878158631SZbigniew Kurzynski 859c1019828SEd Tanous if (auth.cookie) 86078158631SZbigniew Kurzynski { 86125b54dbaSEd Tanous if constexpr (!BMCWEB_COOKIE_AUTH) 86225b54dbaSEd Tanous { 8630fda0f12SGeorge Liu messages::actionNotSupported( 8640fda0f12SGeorge Liu asyncResp->res, 8650fda0f12SGeorge Liu "Setting Cookie when cookie-auth feature is disabled"); 866f16f6263SAlan Kuo return; 86725b54dbaSEd Tanous } 868c1019828SEd Tanous authMethodsConfig.cookie = *auth.cookie; 86978158631SZbigniew Kurzynski } 87078158631SZbigniew Kurzynski 871c1019828SEd Tanous if (auth.sessionToken) 87278158631SZbigniew Kurzynski { 87325b54dbaSEd Tanous if constexpr (!BMCWEB_SESSION_AUTH) 87425b54dbaSEd Tanous { 875f16f6263SAlan Kuo messages::actionNotSupported( 8760fda0f12SGeorge Liu asyncResp->res, 8770fda0f12SGeorge Liu "Setting SessionToken when session-auth feature is disabled"); 878f16f6263SAlan Kuo return; 87925b54dbaSEd Tanous } 880c1019828SEd Tanous authMethodsConfig.sessionToken = *auth.sessionToken; 88178158631SZbigniew Kurzynski } 88278158631SZbigniew Kurzynski 883c1019828SEd Tanous if (auth.xToken) 88478158631SZbigniew Kurzynski { 88525b54dbaSEd Tanous if constexpr (!BMCWEB_XTOKEN_AUTH) 88625b54dbaSEd Tanous { 8870fda0f12SGeorge Liu messages::actionNotSupported( 8880fda0f12SGeorge Liu asyncResp->res, 8890fda0f12SGeorge Liu "Setting XToken when xtoken-auth feature is disabled"); 890f16f6263SAlan Kuo return; 89125b54dbaSEd Tanous } 892c1019828SEd Tanous authMethodsConfig.xtoken = *auth.xToken; 89378158631SZbigniew Kurzynski } 89478158631SZbigniew Kurzynski 895c1019828SEd Tanous if (auth.tls) 896501f1e58SZbigniew Kurzynski { 89725b54dbaSEd Tanous if constexpr (!BMCWEB_MUTUAL_TLS_AUTH) 89825b54dbaSEd Tanous { 8990fda0f12SGeorge Liu messages::actionNotSupported( 9000fda0f12SGeorge Liu asyncResp->res, 9010fda0f12SGeorge Liu "Setting TLS when mutual-tls-auth feature is disabled"); 902f16f6263SAlan Kuo return; 90325b54dbaSEd Tanous } 904c1019828SEd Tanous authMethodsConfig.tls = *auth.tls; 905501f1e58SZbigniew Kurzynski } 906501f1e58SZbigniew Kurzynski 90778158631SZbigniew Kurzynski if (!authMethodsConfig.basic && !authMethodsConfig.cookie && 908501f1e58SZbigniew Kurzynski !authMethodsConfig.sessionToken && !authMethodsConfig.xtoken && 909501f1e58SZbigniew Kurzynski !authMethodsConfig.tls) 91078158631SZbigniew Kurzynski { 91178158631SZbigniew Kurzynski // Do not allow user to disable everything 91278158631SZbigniew Kurzynski messages::actionNotSupported(asyncResp->res, 91378158631SZbigniew Kurzynski "of disabling all available methods"); 91478158631SZbigniew Kurzynski return; 91578158631SZbigniew Kurzynski } 91678158631SZbigniew Kurzynski 91752cc112dSEd Tanous persistent_data::SessionStore::getInstance().updateAuthMethodsConfig( 91852cc112dSEd Tanous authMethodsConfig); 91978158631SZbigniew Kurzynski // Save configuration immediately 92052cc112dSEd Tanous persistent_data::getConfig().writeData(); 92178158631SZbigniew Kurzynski 92278158631SZbigniew Kurzynski messages::success(asyncResp->res); 92378158631SZbigniew Kurzynski } 92478158631SZbigniew Kurzynski 9258a07d286SRatan Gupta /** 9268a07d286SRatan Gupta * @brief Get the required values from the given JSON, validates the 9278a07d286SRatan Gupta * value and create the LDAP config object. 9288a07d286SRatan Gupta * @param input JSON data 9298a07d286SRatan Gupta * @param asyncResp pointer to the JSON response 9308a07d286SRatan Gupta * @param serverType Type of LDAP server(openLDAP/ActiveDirectory) 9318a07d286SRatan Gupta */ 9328a07d286SRatan Gupta 93310cb44f3SEd Tanous struct LdapPatchParams 93410cb44f3SEd Tanous { 93510cb44f3SEd Tanous std::optional<std::string> authType; 93610cb44f3SEd Tanous std::optional<std::vector<std::string>> serviceAddressList; 93710cb44f3SEd Tanous std::optional<bool> serviceEnabled; 93810cb44f3SEd Tanous std::optional<std::vector<std::string>> baseDNList; 93910cb44f3SEd Tanous std::optional<std::string> userNameAttribute; 94010cb44f3SEd Tanous std::optional<std::string> groupsAttribute; 94110cb44f3SEd Tanous std::optional<std::string> userName; 94210cb44f3SEd Tanous std::optional<std::string> password; 94310cb44f3SEd Tanous std::optional< 94410cb44f3SEd Tanous std::vector<std::variant<nlohmann::json::object_t, std::nullptr_t>>> 94510cb44f3SEd Tanous remoteRoleMapData; 94610cb44f3SEd Tanous }; 94710cb44f3SEd Tanous 94810cb44f3SEd Tanous inline void handleLDAPPatch(LdapPatchParams&& input, 9498d1b46d7Szhanghch05 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 9508a07d286SRatan Gupta const std::string& serverType) 9518a07d286SRatan Gupta { 952eb2bbe56SRatan Gupta std::string dbusObjectPath; 953eb2bbe56SRatan Gupta if (serverType == "ActiveDirectory") 954eb2bbe56SRatan Gupta { 9552c70f800SEd Tanous dbusObjectPath = adConfigObject; 956eb2bbe56SRatan Gupta } 957eb2bbe56SRatan Gupta else if (serverType == "LDAP") 958eb2bbe56SRatan Gupta { 95923a21a1cSEd Tanous dbusObjectPath = ldapConfigObjectName; 960eb2bbe56SRatan Gupta } 961cb13a392SEd Tanous else 962cb13a392SEd Tanous { 96310cb44f3SEd Tanous BMCWEB_LOG_ERROR("serverType wasn't AD or LDAP but was {}????", 96410cb44f3SEd Tanous serverType); 965cb13a392SEd Tanous return; 966cb13a392SEd Tanous } 967eb2bbe56SRatan Gupta 96810cb44f3SEd Tanous if (input.authType && *input.authType != "UsernameAndPassword") 9698a07d286SRatan Gupta { 97010cb44f3SEd Tanous messages::propertyValueNotInList(asyncResp->res, *input.authType, 971c1019828SEd Tanous "AuthenticationType"); 972c1019828SEd Tanous return; 9738a07d286SRatan Gupta } 974c1019828SEd Tanous 97510cb44f3SEd Tanous if (input.serviceAddressList) 9768a07d286SRatan Gupta { 97710cb44f3SEd Tanous if (input.serviceAddressList->empty()) 9788a07d286SRatan Gupta { 979e2616cc5SEd Tanous messages::propertyValueNotInList( 98010cb44f3SEd Tanous asyncResp->res, *input.serviceAddressList, "ServiceAddress"); 9818a07d286SRatan Gupta return; 9828a07d286SRatan Gupta } 9838a07d286SRatan Gupta } 98410cb44f3SEd Tanous if (input.baseDNList) 9858a07d286SRatan Gupta { 98610cb44f3SEd Tanous if (input.baseDNList->empty()) 9878a07d286SRatan Gupta { 98810cb44f3SEd Tanous messages::propertyValueNotInList(asyncResp->res, *input.baseDNList, 9898a07d286SRatan Gupta "BaseDistinguishedNames"); 9908a07d286SRatan Gupta return; 9918a07d286SRatan Gupta } 9928a07d286SRatan Gupta } 9938a07d286SRatan Gupta 9948a07d286SRatan Gupta // nothing to update, then return 99510cb44f3SEd Tanous if (!input.userName && !input.password && !input.serviceAddressList && 99610cb44f3SEd Tanous !input.baseDNList && !input.userNameAttribute && 99710cb44f3SEd Tanous !input.groupsAttribute && !input.serviceEnabled && 99810cb44f3SEd Tanous !input.remoteRoleMapData) 9998a07d286SRatan Gupta { 10008a07d286SRatan Gupta return; 10018a07d286SRatan Gupta } 10028a07d286SRatan Gupta 10038a07d286SRatan Gupta // Get the existing resource first then keep modifying 10048a07d286SRatan Gupta // whenever any property gets updated. 1005bd79bce8SPatrick Williams getLDAPConfigData(serverType, [asyncResp, input = std::move(input), 100610cb44f3SEd Tanous dbusObjectPath = std::move(dbusObjectPath)]( 1007bd79bce8SPatrick Williams bool success, 1008bd79bce8SPatrick Williams const LDAPConfigData& confData, 1009c1019828SEd Tanous const std::string& serverT) mutable { 10108a07d286SRatan Gupta if (!success) 10118a07d286SRatan Gupta { 10128a07d286SRatan Gupta messages::internalError(asyncResp->res); 10138a07d286SRatan Gupta return; 10148a07d286SRatan Gupta } 10156c51eab1SEd Tanous parseLDAPConfigData(asyncResp->res.jsonValue, confData, serverT); 10168a07d286SRatan Gupta if (confData.serviceEnabled) 10178a07d286SRatan Gupta { 10188a07d286SRatan Gupta // Disable the service first and update the rest of 10198a07d286SRatan Gupta // the properties. 10206c51eab1SEd Tanous handleServiceEnablePatch(false, asyncResp, serverT, dbusObjectPath); 10218a07d286SRatan Gupta } 10228a07d286SRatan Gupta 102310cb44f3SEd Tanous if (input.serviceAddressList) 10248a07d286SRatan Gupta { 102510cb44f3SEd Tanous handleServiceAddressPatch(*input.serviceAddressList, asyncResp, 102610cb44f3SEd Tanous serverT, dbusObjectPath); 102710cb44f3SEd Tanous } 102810cb44f3SEd Tanous if (input.userName) 102910cb44f3SEd Tanous { 103010cb44f3SEd Tanous handleUserNamePatch(*input.userName, asyncResp, serverT, 10316c51eab1SEd Tanous dbusObjectPath); 10328a07d286SRatan Gupta } 103310cb44f3SEd Tanous if (input.password) 10348a07d286SRatan Gupta { 103510cb44f3SEd Tanous handlePasswordPatch(*input.password, asyncResp, serverT, 103610cb44f3SEd Tanous dbusObjectPath); 10378a07d286SRatan Gupta } 10388a07d286SRatan Gupta 103910cb44f3SEd Tanous if (input.baseDNList) 10408a07d286SRatan Gupta { 104110cb44f3SEd Tanous handleBaseDNPatch(*input.baseDNList, asyncResp, serverT, 10426c51eab1SEd Tanous dbusObjectPath); 10438a07d286SRatan Gupta } 104410cb44f3SEd Tanous if (input.userNameAttribute) 10458a07d286SRatan Gupta { 104610cb44f3SEd Tanous handleUserNameAttrPatch(*input.userNameAttribute, asyncResp, 104710cb44f3SEd Tanous serverT, dbusObjectPath); 104810cb44f3SEd Tanous } 104910cb44f3SEd Tanous if (input.groupsAttribute) 105010cb44f3SEd Tanous { 105110cb44f3SEd Tanous handleGroupNameAttrPatch(*input.groupsAttribute, asyncResp, serverT, 10526c51eab1SEd Tanous dbusObjectPath); 10538a07d286SRatan Gupta } 105410cb44f3SEd Tanous if (input.serviceEnabled) 10558a07d286SRatan Gupta { 10568a07d286SRatan Gupta // if user has given the value as true then enable 10578a07d286SRatan Gupta // the service. if user has given false then no-op 10588a07d286SRatan Gupta // as service is already stopped. 105910cb44f3SEd Tanous if (*input.serviceEnabled) 10608a07d286SRatan Gupta { 106110cb44f3SEd Tanous handleServiceEnablePatch(*input.serviceEnabled, asyncResp, 106210cb44f3SEd Tanous serverT, dbusObjectPath); 10638a07d286SRatan Gupta } 10648a07d286SRatan Gupta } 10658a07d286SRatan Gupta else 10668a07d286SRatan Gupta { 10678a07d286SRatan Gupta // if user has not given the service enabled value 10688a07d286SRatan Gupta // then revert it to the same state as it was 10698a07d286SRatan Gupta // before. 10708a07d286SRatan Gupta handleServiceEnablePatch(confData.serviceEnabled, asyncResp, 107123a21a1cSEd Tanous serverT, dbusObjectPath); 10728a07d286SRatan Gupta } 107306785244SRatan Gupta 107410cb44f3SEd Tanous if (input.remoteRoleMapData) 107506785244SRatan Gupta { 10766c51eab1SEd Tanous handleRoleMapPatch(asyncResp, confData.groupRoleList, serverT, 107710cb44f3SEd Tanous *input.remoteRoleMapData); 107806785244SRatan Gupta } 10798a07d286SRatan Gupta }); 10808a07d286SRatan Gupta } 1081d4b5443fSEd Tanous 1082492ec93aSEd Tanous struct UserUpdateParams 10831abe55efSEd Tanous { 1084492ec93aSEd Tanous std::string username; 1085492ec93aSEd Tanous std::optional<std::string> password; 1086492ec93aSEd Tanous std::optional<bool> enabled; 1087492ec93aSEd Tanous std::optional<std::string> roleId; 1088492ec93aSEd Tanous std::optional<bool> locked; 1089492ec93aSEd Tanous std::optional<std::vector<std::string>> accountTypes; 1090492ec93aSEd Tanous bool userSelf; 1091492ec93aSEd Tanous std::shared_ptr<persistent_data::UserSession> session; 1092492ec93aSEd Tanous std::string dbusObjectPath; 1093492ec93aSEd Tanous }; 10946c51eab1SEd Tanous 1095492ec93aSEd Tanous inline void 1096492ec93aSEd Tanous afterVerifyUserExists(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1097492ec93aSEd Tanous const UserUpdateParams& params, int rc) 1098492ec93aSEd Tanous { 1099e662eae8SEd Tanous if (rc <= 0) 11006c51eab1SEd Tanous { 1101d8a5d5d8SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "ManagerAccount", 1102492ec93aSEd Tanous params.username); 11036c51eab1SEd Tanous return; 11046c51eab1SEd Tanous } 11056c51eab1SEd Tanous 1106492ec93aSEd Tanous if (params.password) 11076c51eab1SEd Tanous { 1108492ec93aSEd Tanous int retval = pamUpdatePassword(params.username, *params.password); 11096c51eab1SEd Tanous 11106c51eab1SEd Tanous if (retval == PAM_USER_UNKNOWN) 11116c51eab1SEd Tanous { 1112d8a5d5d8SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "ManagerAccount", 1113492ec93aSEd Tanous params.username); 11146c51eab1SEd Tanous } 11156c51eab1SEd Tanous else if (retval == PAM_AUTHTOK_ERR) 11166c51eab1SEd Tanous { 11176c51eab1SEd Tanous // If password is invalid 11189bd80831SJason M. Bills messages::propertyValueFormatError(asyncResp->res, nullptr, 11199bd80831SJason M. Bills "Password"); 112062598e31SEd Tanous BMCWEB_LOG_ERROR("pamUpdatePassword Failed"); 11216c51eab1SEd Tanous } 11226c51eab1SEd Tanous else if (retval != PAM_SUCCESS) 11236c51eab1SEd Tanous { 11246c51eab1SEd Tanous messages::internalError(asyncResp->res); 11256c51eab1SEd Tanous return; 11266c51eab1SEd Tanous } 1127e7b1b62bSEd Tanous else 1128e7b1b62bSEd Tanous { 1129bd79bce8SPatrick Williams // Remove existing sessions of the user when password 1130bd79bce8SPatrick Williams // changed 1131e518ef32SRavi Teja persistent_data::SessionStore::getInstance() 1132492ec93aSEd Tanous .removeSessionsByUsernameExceptSession(params.username, 1133492ec93aSEd Tanous params.session); 1134e7b1b62bSEd Tanous messages::success(asyncResp->res); 1135e7b1b62bSEd Tanous } 11366c51eab1SEd Tanous } 11376c51eab1SEd Tanous 1138492ec93aSEd Tanous if (params.enabled) 11396c51eab1SEd Tanous { 1140bd79bce8SPatrick Williams setDbusProperty( 1141bd79bce8SPatrick Williams asyncResp, "Enabled", "xyz.openbmc_project.User.Manager", 1142492ec93aSEd Tanous params.dbusObjectPath, "xyz.openbmc_project.User.Attributes", 1143492ec93aSEd Tanous "UserEnabled", *params.enabled); 11446c51eab1SEd Tanous } 11456c51eab1SEd Tanous 1146492ec93aSEd Tanous if (params.roleId) 11476c51eab1SEd Tanous { 1148492ec93aSEd Tanous std::string priv = getPrivilegeFromRoleId(*params.roleId); 11496c51eab1SEd Tanous if (priv.empty()) 11506c51eab1SEd Tanous { 1151492ec93aSEd Tanous messages::propertyValueNotInList(asyncResp->res, true, "Locked"); 11526c51eab1SEd Tanous return; 11536c51eab1SEd Tanous } 1154492ec93aSEd Tanous setDbusProperty(asyncResp, "RoleId", "xyz.openbmc_project.User.Manager", 1155492ec93aSEd Tanous params.dbusObjectPath, 1156492ec93aSEd Tanous "xyz.openbmc_project.User.Attributes", "UserPrivilege", 1157492ec93aSEd Tanous priv); 11586c51eab1SEd Tanous } 11596c51eab1SEd Tanous 1160492ec93aSEd Tanous if (params.locked) 11616c51eab1SEd Tanous { 11626c51eab1SEd Tanous // admin can unlock the account which is locked by 11636c51eab1SEd Tanous // successive authentication failures but admin should 11646c51eab1SEd Tanous // not be allowed to lock an account. 1165492ec93aSEd Tanous if (*params.locked) 11666c51eab1SEd Tanous { 1167492ec93aSEd Tanous messages::propertyValueNotInList(asyncResp->res, "true", "Locked"); 11686c51eab1SEd Tanous return; 11696c51eab1SEd Tanous } 1170492ec93aSEd Tanous setDbusProperty(asyncResp, "Locked", "xyz.openbmc_project.User.Manager", 1171492ec93aSEd Tanous params.dbusObjectPath, 1172492ec93aSEd Tanous "xyz.openbmc_project.User.Attributes", 1173492ec93aSEd Tanous "UserLockedForFailedAttempt", *params.locked); 11746c51eab1SEd Tanous } 117558345856SAbhishek Patel 1176492ec93aSEd Tanous if (params.accountTypes) 117758345856SAbhishek Patel { 1178492ec93aSEd Tanous patchAccountTypes(*params.accountTypes, asyncResp, 1179492ec93aSEd Tanous params.dbusObjectPath, params.userSelf); 118058345856SAbhishek Patel } 1181492ec93aSEd Tanous } 1182492ec93aSEd Tanous 1183492ec93aSEd Tanous inline void updateUserProperties( 1184492ec93aSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1185492ec93aSEd Tanous const std::string& username, const std::optional<std::string>& password, 1186492ec93aSEd Tanous const std::optional<bool>& enabled, 1187492ec93aSEd Tanous const std::optional<std::string>& roleId, const std::optional<bool>& locked, 1188492ec93aSEd Tanous const std::optional<std::vector<std::string>>& accountTypes, bool userSelf, 1189492ec93aSEd Tanous const std::shared_ptr<persistent_data::UserSession>& session) 1190492ec93aSEd Tanous { 1191492ec93aSEd Tanous sdbusplus::message::object_path tempObjPath(rootUserDbusPath); 1192492ec93aSEd Tanous tempObjPath /= username; 1193492ec93aSEd Tanous std::string dbusObjectPath(tempObjPath); 1194492ec93aSEd Tanous 1195492ec93aSEd Tanous UserUpdateParams params{username, password, enabled, 1196492ec93aSEd Tanous roleId, locked, accountTypes, 1197492ec93aSEd Tanous userSelf, session, dbusObjectPath}; 1198492ec93aSEd Tanous 1199492ec93aSEd Tanous dbus::utility::checkDbusPathExists( 1200492ec93aSEd Tanous dbusObjectPath, 1201492ec93aSEd Tanous std::bind_front(afterVerifyUserExists, asyncResp, std::move(params))); 12026c51eab1SEd Tanous } 12036c51eab1SEd Tanous 12044c7d4d33SEd Tanous inline void handleAccountServiceHead( 12054c7d4d33SEd Tanous App& app, const crow::Request& req, 12061ef4c342SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 12076c51eab1SEd Tanous { 12083ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 120945ca1b86SEd Tanous { 121045ca1b86SEd Tanous return; 121145ca1b86SEd Tanous } 12124c7d4d33SEd Tanous asyncResp->res.addHeader( 12134c7d4d33SEd Tanous boost::beast::http::field::link, 12144c7d4d33SEd Tanous "</redfish/v1/JsonSchemas/AccountService/AccountService.json>; rel=describedby"); 12154c7d4d33SEd Tanous } 12164c7d4d33SEd Tanous 12174c7d4d33SEd Tanous inline void 12181aa375b8SEd Tanous getClientCertificates(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 12191aa375b8SEd Tanous const nlohmann::json::json_pointer& keyLocation) 12201aa375b8SEd Tanous { 12211aa375b8SEd Tanous boost::urls::url url( 12221aa375b8SEd Tanous "/redfish/v1/AccountService/MultiFactorAuth/ClientCertificate/Certificates"); 12231aa375b8SEd Tanous std::array<std::string_view, 1> interfaces = { 12241aa375b8SEd Tanous "xyz.openbmc_project.Certs.Certificate"}; 12251aa375b8SEd Tanous std::string path = "/xyz/openbmc_project/certs/authority/truststore"; 12261aa375b8SEd Tanous 12271aa375b8SEd Tanous collection_util::getCollectionToKey(asyncResp, url, interfaces, path, 12281aa375b8SEd Tanous keyLocation); 12291aa375b8SEd Tanous } 12301aa375b8SEd Tanous 12311aa375b8SEd Tanous inline void handleAccountServiceClientCertificatesInstanceHead( 12321aa375b8SEd Tanous App& app, const crow::Request& req, 12331aa375b8SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 12341aa375b8SEd Tanous const std::string& /*id*/) 12351aa375b8SEd Tanous { 12361aa375b8SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 12371aa375b8SEd Tanous { 12381aa375b8SEd Tanous return; 12391aa375b8SEd Tanous } 12401aa375b8SEd Tanous 12411aa375b8SEd Tanous asyncResp->res.addHeader( 12421aa375b8SEd Tanous boost::beast::http::field::link, 12431aa375b8SEd Tanous "</redfish/v1/JsonSchemas/Certificate/Certificate.json>; rel=describedby"); 12441aa375b8SEd Tanous } 12451aa375b8SEd Tanous 12461aa375b8SEd Tanous inline void handleAccountServiceClientCertificatesInstanceGet( 12471aa375b8SEd Tanous App& app, const crow::Request& req, 12481aa375b8SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id) 12491aa375b8SEd Tanous { 12501aa375b8SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 12511aa375b8SEd Tanous { 12521aa375b8SEd Tanous return; 12531aa375b8SEd Tanous } 12541aa375b8SEd Tanous BMCWEB_LOG_DEBUG("ClientCertificate Certificate ID={}", id); 12551aa375b8SEd Tanous const boost::urls::url certURL = boost::urls::format( 12561aa375b8SEd Tanous "/redfish/v1/AccountService/MultiFactorAuth/ClientCertificate/Certificates/{}", 12571aa375b8SEd Tanous id); 12581aa375b8SEd Tanous std::string objPath = 12591aa375b8SEd Tanous sdbusplus::message::object_path(certs::authorityObjectPath) / id; 12601aa375b8SEd Tanous getCertificateProperties( 12611aa375b8SEd Tanous asyncResp, objPath, 12621aa375b8SEd Tanous "xyz.openbmc_project.Certs.Manager.Authority.Truststore", id, certURL, 12631aa375b8SEd Tanous "Client Certificate"); 12641aa375b8SEd Tanous } 12651aa375b8SEd Tanous 12661aa375b8SEd Tanous inline void handleAccountServiceClientCertificatesHead( 12671aa375b8SEd Tanous App& app, const crow::Request& req, 12681aa375b8SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 12691aa375b8SEd Tanous { 12701aa375b8SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 12711aa375b8SEd Tanous { 12721aa375b8SEd Tanous return; 12731aa375b8SEd Tanous } 12741aa375b8SEd Tanous 12751aa375b8SEd Tanous asyncResp->res.addHeader( 12761aa375b8SEd Tanous boost::beast::http::field::link, 12771aa375b8SEd Tanous "</redfish/v1/JsonSchemas/CertificateCollection/CertificateCollection.json>; rel=describedby"); 12781aa375b8SEd Tanous } 12791aa375b8SEd Tanous 12801aa375b8SEd Tanous inline void handleAccountServiceClientCertificatesGet( 12811aa375b8SEd Tanous App& app, const crow::Request& req, 12821aa375b8SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 12831aa375b8SEd Tanous { 12841aa375b8SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 12851aa375b8SEd Tanous { 12861aa375b8SEd Tanous return; 12871aa375b8SEd Tanous } 12881aa375b8SEd Tanous getClientCertificates(asyncResp, "/Members"_json_pointer); 12891aa375b8SEd Tanous } 12901aa375b8SEd Tanous 12913ce3688aSEd Tanous using account_service::CertificateMappingAttribute; 12923ce3688aSEd Tanous using persistent_data::MTLSCommonNameParseMode; 12933ce3688aSEd Tanous inline CertificateMappingAttribute 12943ce3688aSEd Tanous getCertificateMapping(MTLSCommonNameParseMode parse) 12953ce3688aSEd Tanous { 12963ce3688aSEd Tanous switch (parse) 12973ce3688aSEd Tanous { 12983ce3688aSEd Tanous case MTLSCommonNameParseMode::CommonName: 12993ce3688aSEd Tanous { 13003ce3688aSEd Tanous return CertificateMappingAttribute::CommonName; 13013ce3688aSEd Tanous } 13023ce3688aSEd Tanous break; 13033ce3688aSEd Tanous case MTLSCommonNameParseMode::Whole: 13043ce3688aSEd Tanous { 13053ce3688aSEd Tanous return CertificateMappingAttribute::Whole; 13063ce3688aSEd Tanous } 13073ce3688aSEd Tanous break; 13083ce3688aSEd Tanous case MTLSCommonNameParseMode::UserPrincipalName: 13093ce3688aSEd Tanous { 13103ce3688aSEd Tanous return CertificateMappingAttribute::UserPrincipalName; 13113ce3688aSEd Tanous } 13123ce3688aSEd Tanous break; 13133ce3688aSEd Tanous 13143ce3688aSEd Tanous case MTLSCommonNameParseMode::Meta: 13153ce3688aSEd Tanous { 13163ce3688aSEd Tanous if constexpr (BMCWEB_META_TLS_COMMON_NAME_PARSING) 13173ce3688aSEd Tanous { 13183ce3688aSEd Tanous return CertificateMappingAttribute::CommonName; 13193ce3688aSEd Tanous } 13203ce3688aSEd Tanous } 13213ce3688aSEd Tanous break; 13223ce3688aSEd Tanous default: 13233ce3688aSEd Tanous { 13243ce3688aSEd Tanous return CertificateMappingAttribute::Invalid; 13253ce3688aSEd Tanous } 13263ce3688aSEd Tanous break; 13273ce3688aSEd Tanous } 13283ce3688aSEd Tanous } 13293ce3688aSEd Tanous 13301aa375b8SEd Tanous inline void 13314c7d4d33SEd Tanous handleAccountServiceGet(App& app, const crow::Request& req, 13324c7d4d33SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 13334c7d4d33SEd Tanous { 1334afd369c6SJiaqing Zhao if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 1335afd369c6SJiaqing Zhao { 1336afd369c6SJiaqing Zhao return; 1337afd369c6SJiaqing Zhao } 13383e72c202SNinad Palsule 13393e72c202SNinad Palsule if (req.session == nullptr) 13403e72c202SNinad Palsule { 13413e72c202SNinad Palsule messages::internalError(asyncResp->res); 13423e72c202SNinad Palsule return; 13433e72c202SNinad Palsule } 13443e72c202SNinad Palsule 1345c1019828SEd Tanous const persistent_data::AuthConfigMethods& authMethodsConfig = 1346c1019828SEd Tanous persistent_data::SessionStore::getInstance().getAuthMethodsConfig(); 1347c1019828SEd Tanous 1348afd369c6SJiaqing Zhao asyncResp->res.addHeader( 1349afd369c6SJiaqing Zhao boost::beast::http::field::link, 1350afd369c6SJiaqing Zhao "</redfish/v1/JsonSchemas/AccountService/AccountService.json>; rel=describedby"); 1351afd369c6SJiaqing Zhao 13521476687dSEd Tanous nlohmann::json& json = asyncResp->res.jsonValue; 13531476687dSEd Tanous json["@odata.id"] = "/redfish/v1/AccountService"; 1354482a69e7SRavi Teja json["@odata.type"] = "#AccountService.v1_15_0.AccountService"; 13551476687dSEd Tanous json["Id"] = "AccountService"; 13561476687dSEd Tanous json["Name"] = "Account Service"; 13571476687dSEd Tanous json["Description"] = "Account Service"; 13581476687dSEd Tanous json["ServiceEnabled"] = true; 13591476687dSEd Tanous json["MaxPasswordLength"] = 20; 13601ef4c342SEd Tanous json["Accounts"]["@odata.id"] = "/redfish/v1/AccountService/Accounts"; 13611476687dSEd Tanous json["Roles"]["@odata.id"] = "/redfish/v1/AccountService/Roles"; 1362482a69e7SRavi Teja json["HTTPBasicAuth"] = authMethodsConfig.basic 1363482a69e7SRavi Teja ? account_service::BasicAuthState::Enabled 1364482a69e7SRavi Teja : account_service::BasicAuthState::Disabled; 1365482a69e7SRavi Teja 1366482a69e7SRavi Teja nlohmann::json::array_t allowed; 1367482a69e7SRavi Teja allowed.emplace_back(account_service::BasicAuthState::Enabled); 1368482a69e7SRavi Teja allowed.emplace_back(account_service::BasicAuthState::Disabled); 1369482a69e7SRavi Teja json["HTTPBasicAuth@AllowableValues"] = std::move(allowed); 1370482a69e7SRavi Teja 13711aa375b8SEd Tanous nlohmann::json::object_t clientCertificate; 13721aa375b8SEd Tanous clientCertificate["Enabled"] = authMethodsConfig.tls; 13733281bcf1SEd Tanous clientCertificate["RespondToUnauthenticatedClients"] = 13743281bcf1SEd Tanous !authMethodsConfig.tlsStrict; 13753ce3688aSEd Tanous 13763ce3688aSEd Tanous using account_service::CertificateMappingAttribute; 13773ce3688aSEd Tanous 13783ce3688aSEd Tanous CertificateMappingAttribute mapping = 13793ce3688aSEd Tanous getCertificateMapping(authMethodsConfig.mTLSCommonNameParsingMode); 13803ce3688aSEd Tanous if (mapping == CertificateMappingAttribute::Invalid) 13813ce3688aSEd Tanous { 13823ce3688aSEd Tanous messages::internalError(asyncResp->res); 13833ce3688aSEd Tanous } 13843ce3688aSEd Tanous else 13853ce3688aSEd Tanous { 13863ce3688aSEd Tanous clientCertificate["CertificateMappingAttribute"] = mapping; 13873ce3688aSEd Tanous } 13881aa375b8SEd Tanous nlohmann::json::object_t certificates; 13891aa375b8SEd Tanous certificates["@odata.id"] = 13901aa375b8SEd Tanous "/redfish/v1/AccountService/MultiFactorAuth/ClientCertificate/Certificates"; 13911aa375b8SEd Tanous certificates["@odata.type"] = 13921aa375b8SEd Tanous "#CertificateCollection.CertificateCollection"; 13931aa375b8SEd Tanous clientCertificate["Certificates"] = std::move(certificates); 13941aa375b8SEd Tanous json["MultiFactorAuth"]["ClientCertificate"] = std::move(clientCertificate); 13951aa375b8SEd Tanous 13961aa375b8SEd Tanous getClientCertificates( 13971aa375b8SEd Tanous asyncResp, 13981aa375b8SEd Tanous "/MultiFactorAuth/ClientCertificate/Certificates/Members"_json_pointer); 13991aa375b8SEd Tanous 14001476687dSEd Tanous json["Oem"]["OpenBMC"]["@odata.type"] = 14015b5574acSEd Tanous "#OpenBMCAccountService.v1_0_0.AccountService"; 14021476687dSEd Tanous json["Oem"]["OpenBMC"]["@odata.id"] = 14031476687dSEd Tanous "/redfish/v1/AccountService#/Oem/OpenBMC"; 14041476687dSEd Tanous json["Oem"]["OpenBMC"]["AuthMethods"]["BasicAuth"] = 14051476687dSEd Tanous authMethodsConfig.basic; 14061476687dSEd Tanous json["Oem"]["OpenBMC"]["AuthMethods"]["SessionToken"] = 14071476687dSEd Tanous authMethodsConfig.sessionToken; 14081ef4c342SEd Tanous json["Oem"]["OpenBMC"]["AuthMethods"]["XToken"] = authMethodsConfig.xtoken; 14091ef4c342SEd Tanous json["Oem"]["OpenBMC"]["AuthMethods"]["Cookie"] = authMethodsConfig.cookie; 14101ef4c342SEd Tanous json["Oem"]["OpenBMC"]["AuthMethods"]["TLS"] = authMethodsConfig.tls; 14111476687dSEd Tanous 14121ef4c342SEd Tanous // /redfish/v1/AccountService/LDAP/Certificates is something only 14131ef4c342SEd Tanous // ConfigureManager can access then only display when the user has 14141ef4c342SEd Tanous // permissions ConfigureManager 141572048780SAbhishek Patel Privileges effectiveUserPrivileges = 14163e72c202SNinad Palsule redfish::getUserPrivileges(*req.session); 141772048780SAbhishek Patel 141872048780SAbhishek Patel if (isOperationAllowedWithPrivileges({{"ConfigureManager"}}, 141972048780SAbhishek Patel effectiveUserPrivileges)) 142072048780SAbhishek Patel { 14211ef4c342SEd Tanous asyncResp->res.jsonValue["LDAP"]["Certificates"]["@odata.id"] = 14221476687dSEd Tanous "/redfish/v1/AccountService/LDAP/Certificates"; 142372048780SAbhishek Patel } 1424deae6a78SEd Tanous dbus::utility::getAllProperties( 1425deae6a78SEd Tanous "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user", 1426deae6a78SEd Tanous "xyz.openbmc_project.User.AccountPolicy", 14275e7e2dc5SEd Tanous [asyncResp](const boost::system::error_code& ec, 14281ef4c342SEd Tanous const dbus::utility::DBusPropertiesMap& propertiesList) { 14293d958bbcSAppaRao Puli if (ec) 14303d958bbcSAppaRao Puli { 14313d958bbcSAppaRao Puli messages::internalError(asyncResp->res); 14323d958bbcSAppaRao Puli return; 14333d958bbcSAppaRao Puli } 1434d1bde9e5SKrzysztof Grobelny 143562598e31SEd Tanous BMCWEB_LOG_DEBUG("Got {} properties for AccountService", 143662598e31SEd Tanous propertiesList.size()); 1437d1bde9e5SKrzysztof Grobelny 1438d1bde9e5SKrzysztof Grobelny const uint8_t* minPasswordLength = nullptr; 1439d1bde9e5SKrzysztof Grobelny const uint32_t* accountUnlockTimeout = nullptr; 1440d1bde9e5SKrzysztof Grobelny const uint16_t* maxLoginAttemptBeforeLockout = nullptr; 1441d1bde9e5SKrzysztof Grobelny 1442d1bde9e5SKrzysztof Grobelny const bool success = sdbusplus::unpackPropertiesNoThrow( 1443d1bde9e5SKrzysztof Grobelny dbus_utils::UnpackErrorPrinter(), propertiesList, 1444d1bde9e5SKrzysztof Grobelny "MinPasswordLength", minPasswordLength, "AccountUnlockTimeout", 1445d1bde9e5SKrzysztof Grobelny accountUnlockTimeout, "MaxLoginAttemptBeforeLockout", 1446d1bde9e5SKrzysztof Grobelny maxLoginAttemptBeforeLockout); 1447d1bde9e5SKrzysztof Grobelny 1448d1bde9e5SKrzysztof Grobelny if (!success) 14493d958bbcSAppaRao Puli { 1450d1bde9e5SKrzysztof Grobelny messages::internalError(asyncResp->res); 1451d1bde9e5SKrzysztof Grobelny return; 14523d958bbcSAppaRao Puli } 1453d1bde9e5SKrzysztof Grobelny 1454d1bde9e5SKrzysztof Grobelny if (minPasswordLength != nullptr) 14553d958bbcSAppaRao Puli { 1456bd79bce8SPatrick Williams asyncResp->res.jsonValue["MinPasswordLength"] = 1457bd79bce8SPatrick Williams *minPasswordLength; 14583d958bbcSAppaRao Puli } 1459d1bde9e5SKrzysztof Grobelny 1460d1bde9e5SKrzysztof Grobelny if (accountUnlockTimeout != nullptr) 14613d958bbcSAppaRao Puli { 1462d1bde9e5SKrzysztof Grobelny asyncResp->res.jsonValue["AccountLockoutDuration"] = 1463d1bde9e5SKrzysztof Grobelny *accountUnlockTimeout; 1464d1bde9e5SKrzysztof Grobelny } 1465d1bde9e5SKrzysztof Grobelny 1466d1bde9e5SKrzysztof Grobelny if (maxLoginAttemptBeforeLockout != nullptr) 14673d958bbcSAppaRao Puli { 1468002d39b4SEd Tanous asyncResp->res.jsonValue["AccountLockoutThreshold"] = 1469d1bde9e5SKrzysztof Grobelny *maxLoginAttemptBeforeLockout; 14703d958bbcSAppaRao Puli } 1471d1bde9e5SKrzysztof Grobelny }); 14726973a582SRatan Gupta 147302cad96eSEd Tanous auto callback = [asyncResp](bool success, const LDAPConfigData& confData, 1474ab828d7cSRatan Gupta const std::string& ldapType) { 1475cb13a392SEd Tanous if (!success) 1476cb13a392SEd Tanous { 1477cb13a392SEd Tanous return; 1478cb13a392SEd Tanous } 1479002d39b4SEd Tanous parseLDAPConfigData(asyncResp->res.jsonValue, confData, ldapType); 1480ab828d7cSRatan Gupta }; 1481ab828d7cSRatan Gupta 1482ab828d7cSRatan Gupta getLDAPConfigData("LDAP", callback); 1483ab828d7cSRatan Gupta getLDAPConfigData("ActiveDirectory", callback); 14841ef4c342SEd Tanous } 14856973a582SRatan Gupta 1486bd79bce8SPatrick Williams inline void handleCertificateMappingAttributePatch( 1487bd79bce8SPatrick Williams crow::Response& res, const std::string& certMapAttribute) 14883ce3688aSEd Tanous { 14893ce3688aSEd Tanous MTLSCommonNameParseMode parseMode = 14903ce3688aSEd Tanous persistent_data::getMTLSCommonNameParseMode(certMapAttribute); 14913ce3688aSEd Tanous if (parseMode == MTLSCommonNameParseMode::Invalid) 14923ce3688aSEd Tanous { 14933ce3688aSEd Tanous messages::propertyValueNotInList(res, "CertificateMappingAttribute", 14943ce3688aSEd Tanous certMapAttribute); 14953ce3688aSEd Tanous return; 14963ce3688aSEd Tanous } 14973ce3688aSEd Tanous 14983ce3688aSEd Tanous persistent_data::AuthConfigMethods& authMethodsConfig = 14993ce3688aSEd Tanous persistent_data::SessionStore::getInstance().getAuthMethodsConfig(); 15003ce3688aSEd Tanous authMethodsConfig.mTLSCommonNameParsingMode = parseMode; 15013ce3688aSEd Tanous } 15023ce3688aSEd Tanous 15033281bcf1SEd Tanous inline void handleRespondToUnauthenticatedClientsPatch( 15043281bcf1SEd Tanous App& app, const crow::Request& req, crow::Response& res, 15053281bcf1SEd Tanous bool respondToUnauthenticatedClients) 15063281bcf1SEd Tanous { 15073281bcf1SEd Tanous if (req.session != nullptr) 15083281bcf1SEd Tanous { 15093281bcf1SEd Tanous // Sanity check. If the user isn't currently authenticated with mutual 15103281bcf1SEd Tanous // TLS, they very likely are about to permanently lock themselves out. 15113281bcf1SEd Tanous // Make sure they're using mutual TLS before allowing locking. 15123281bcf1SEd Tanous if (req.session->sessionType != persistent_data::SessionType::MutualTLS) 15133281bcf1SEd Tanous { 15143281bcf1SEd Tanous messages::propertyValueExternalConflict( 15153281bcf1SEd Tanous res, 15163281bcf1SEd Tanous "MultiFactorAuth/ClientCertificate/RespondToUnauthenticatedClients", 15173281bcf1SEd Tanous respondToUnauthenticatedClients); 15183281bcf1SEd Tanous return; 15193281bcf1SEd Tanous } 15203281bcf1SEd Tanous } 15213281bcf1SEd Tanous 15223281bcf1SEd Tanous persistent_data::AuthConfigMethods& authMethodsConfig = 15233281bcf1SEd Tanous persistent_data::SessionStore::getInstance().getAuthMethodsConfig(); 15243281bcf1SEd Tanous 15253281bcf1SEd Tanous // Change the settings 15263281bcf1SEd Tanous authMethodsConfig.tlsStrict = !respondToUnauthenticatedClients; 15273281bcf1SEd Tanous 15283281bcf1SEd Tanous // Write settings to disk 15293281bcf1SEd Tanous persistent_data::getConfig().writeData(); 15303281bcf1SEd Tanous 15313281bcf1SEd Tanous // Trigger a reload, to apply the new settings to new connections 15323281bcf1SEd Tanous app.loadCertificate(); 15333281bcf1SEd Tanous } 15343281bcf1SEd Tanous 15351ef4c342SEd Tanous inline void handleAccountServicePatch( 15361ef4c342SEd Tanous App& app, const crow::Request& req, 15371ef4c342SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 15381ef4c342SEd Tanous { 15393ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 154045ca1b86SEd Tanous { 154145ca1b86SEd Tanous return; 154245ca1b86SEd Tanous } 1543f5ffd806SEd Tanous std::optional<uint32_t> unlockTimeout; 1544f5ffd806SEd Tanous std::optional<uint16_t> lockoutThreshold; 1545ef73ad0dSPaul Fertser std::optional<uint8_t> minPasswordLength; 1546f5ffd806SEd Tanous std::optional<uint16_t> maxPasswordLength; 154710cb44f3SEd Tanous LdapPatchParams ldapObject; 15483ce3688aSEd Tanous std::optional<std::string> certificateMappingAttribute; 15493281bcf1SEd Tanous std::optional<bool> respondToUnauthenticatedClients; 155010cb44f3SEd Tanous LdapPatchParams activeDirectoryObject; 1551c1019828SEd Tanous AuthMethods auth; 1552482a69e7SRavi Teja std::optional<std::string> httpBasicAuth; 15533ce3688aSEd Tanous 1554afc474aeSMyung Bae if (!json_util::readJsonPatch( // 1555afc474aeSMyung Bae req, asyncResp->res, // 1556afc474aeSMyung Bae "AccountLockoutDuration", unlockTimeout, // 1557afc474aeSMyung Bae "AccountLockoutThreshold", lockoutThreshold, // 1558afc474aeSMyung Bae "ActiveDirectory/Authentication/AuthenticationType", 1559afc474aeSMyung Bae activeDirectoryObject.authType, // 1560afc474aeSMyung Bae "ActiveDirectory/Authentication/Password", 1561afc474aeSMyung Bae activeDirectoryObject.password, // 1562afc474aeSMyung Bae "ActiveDirectory/Authentication/Username", 1563afc474aeSMyung Bae activeDirectoryObject.userName, // 1564afc474aeSMyung Bae "ActiveDirectory/LDAPService/SearchSettings/BaseDistinguishedNames", 1565afc474aeSMyung Bae activeDirectoryObject.baseDNList, // 1566afc474aeSMyung Bae "ActiveDirectory/LDAPService/SearchSettings/GroupsAttribute", 1567afc474aeSMyung Bae activeDirectoryObject.groupsAttribute, // 1568afc474aeSMyung Bae "ActiveDirectory/LDAPService/SearchSettings/UsernameAttribute", 1569afc474aeSMyung Bae activeDirectoryObject.userNameAttribute, // 1570afc474aeSMyung Bae "ActiveDirectory/RemoteRoleMapping", 1571afc474aeSMyung Bae activeDirectoryObject.remoteRoleMapData, // 1572afc474aeSMyung Bae "ActiveDirectory/ServiceAddresses", 1573afc474aeSMyung Bae activeDirectoryObject.serviceAddressList, // 1574afc474aeSMyung Bae "ActiveDirectory/ServiceEnabled", 1575afc474aeSMyung Bae activeDirectoryObject.serviceEnabled, // 1576afc474aeSMyung Bae "HTTPBasicAuth", httpBasicAuth, // 1577afc474aeSMyung Bae "LDAP/Authentication/AuthenticationType", ldapObject.authType, // 1578afc474aeSMyung Bae "LDAP/Authentication/Password", ldapObject.password, // 1579afc474aeSMyung Bae "LDAP/Authentication/Username", ldapObject.userName, // 1580afc474aeSMyung Bae "LDAP/LDAPService/SearchSettings/BaseDistinguishedNames", 1581afc474aeSMyung Bae ldapObject.baseDNList, // 1582afc474aeSMyung Bae "LDAP/LDAPService/SearchSettings/GroupsAttribute", 1583afc474aeSMyung Bae ldapObject.groupsAttribute, // 1584afc474aeSMyung Bae "LDAP/LDAPService/SearchSettings/UsernameAttribute", 1585afc474aeSMyung Bae ldapObject.userNameAttribute, // 1586afc474aeSMyung Bae "LDAP/RemoteRoleMapping", ldapObject.remoteRoleMapData, // 1587afc474aeSMyung Bae "LDAP/ServiceAddresses", ldapObject.serviceAddressList, // 1588afc474aeSMyung Bae "LDAP/ServiceEnabled", ldapObject.serviceEnabled, // 1589afc474aeSMyung Bae "MaxPasswordLength", maxPasswordLength, // 1590afc474aeSMyung Bae "MinPasswordLength", minPasswordLength, // 1591afc474aeSMyung Bae "MultiFactorAuth/ClientCertificate/CertificateMappingAttribute", 1592afc474aeSMyung Bae certificateMappingAttribute, // 1593afc474aeSMyung Bae "MultiFactorAuth/ClientCertificate/RespondToUnauthenticatedClients", 1594afc474aeSMyung Bae respondToUnauthenticatedClients, // 1595afc474aeSMyung Bae "Oem/OpenBMC/AuthMethods/BasicAuth", auth.basicAuth, // 1596afc474aeSMyung Bae "Oem/OpenBMC/AuthMethods/Cookie", auth.cookie, // 1597afc474aeSMyung Bae "Oem/OpenBMC/AuthMethods/SessionToken", auth.sessionToken, // 1598afc474aeSMyung Bae "Oem/OpenBMC/AuthMethods/TLS", auth.tls, // 1599afc474aeSMyung Bae "Oem/OpenBMC/AuthMethods/XToken", auth.xToken // 1600afc474aeSMyung Bae )) 1601f5ffd806SEd Tanous { 1602f5ffd806SEd Tanous return; 1603f5ffd806SEd Tanous } 1604f5ffd806SEd Tanous 1605482a69e7SRavi Teja if (httpBasicAuth) 1606482a69e7SRavi Teja { 1607482a69e7SRavi Teja if (*httpBasicAuth == "Enabled") 1608482a69e7SRavi Teja { 1609482a69e7SRavi Teja auth.basicAuth = true; 1610482a69e7SRavi Teja } 1611482a69e7SRavi Teja else if (*httpBasicAuth == "Disabled") 1612482a69e7SRavi Teja { 1613482a69e7SRavi Teja auth.basicAuth = false; 1614482a69e7SRavi Teja } 1615482a69e7SRavi Teja else 1616482a69e7SRavi Teja { 1617482a69e7SRavi Teja messages::propertyValueNotInList(asyncResp->res, "HttpBasicAuth", 1618482a69e7SRavi Teja *httpBasicAuth); 1619482a69e7SRavi Teja } 1620482a69e7SRavi Teja } 1621482a69e7SRavi Teja 16223281bcf1SEd Tanous if (respondToUnauthenticatedClients) 16233281bcf1SEd Tanous { 16243281bcf1SEd Tanous handleRespondToUnauthenticatedClientsPatch( 16253281bcf1SEd Tanous app, req, asyncResp->res, *respondToUnauthenticatedClients); 16263281bcf1SEd Tanous } 16273281bcf1SEd Tanous 16283ce3688aSEd Tanous if (certificateMappingAttribute) 16293ce3688aSEd Tanous { 16303ce3688aSEd Tanous handleCertificateMappingAttributePatch(asyncResp->res, 16313ce3688aSEd Tanous *certificateMappingAttribute); 16323ce3688aSEd Tanous } 16333ce3688aSEd Tanous 1634f5ffd806SEd Tanous if (minPasswordLength) 1635f5ffd806SEd Tanous { 1636d02aad39SEd Tanous setDbusProperty( 1637e93abac6SGinu George asyncResp, "MinPasswordLength", "xyz.openbmc_project.User.Manager", 1638d02aad39SEd Tanous sdbusplus::message::object_path("/xyz/openbmc_project/user"), 16399ae226faSGeorge Liu "xyz.openbmc_project.User.AccountPolicy", "MinPasswordLength", 1640e93abac6SGinu George *minPasswordLength); 1641f5ffd806SEd Tanous } 1642f5ffd806SEd Tanous 1643f5ffd806SEd Tanous if (maxPasswordLength) 1644f5ffd806SEd Tanous { 16451ef4c342SEd Tanous messages::propertyNotWritable(asyncResp->res, "MaxPasswordLength"); 1646f5ffd806SEd Tanous } 1647f5ffd806SEd Tanous 164810cb44f3SEd Tanous handleLDAPPatch(std::move(activeDirectoryObject), asyncResp, 164910cb44f3SEd Tanous "ActiveDirectory"); 165010cb44f3SEd Tanous handleLDAPPatch(std::move(ldapObject), asyncResp, "LDAP"); 1651f5ffd806SEd Tanous 1652c1019828SEd Tanous handleAuthMethodsPatch(asyncResp, auth); 1653f5ffd806SEd Tanous 1654f5ffd806SEd Tanous if (unlockTimeout) 1655f5ffd806SEd Tanous { 1656d02aad39SEd Tanous setDbusProperty( 1657e93abac6SGinu George asyncResp, "AccountLockoutDuration", 1658e93abac6SGinu George "xyz.openbmc_project.User.Manager", 1659d02aad39SEd Tanous sdbusplus::message::object_path("/xyz/openbmc_project/user"), 16609ae226faSGeorge Liu "xyz.openbmc_project.User.AccountPolicy", "AccountUnlockTimeout", 1661e93abac6SGinu George *unlockTimeout); 1662f5ffd806SEd Tanous } 1663f5ffd806SEd Tanous if (lockoutThreshold) 1664f5ffd806SEd Tanous { 1665d02aad39SEd Tanous setDbusProperty( 1666e93abac6SGinu George asyncResp, "AccountLockoutThreshold", 1667e93abac6SGinu George "xyz.openbmc_project.User.Manager", 1668d02aad39SEd Tanous sdbusplus::message::object_path("/xyz/openbmc_project/user"), 16699ae226faSGeorge Liu "xyz.openbmc_project.User.AccountPolicy", 1670e93abac6SGinu George "MaxLoginAttemptBeforeLockout", *lockoutThreshold); 1671f5ffd806SEd Tanous } 16721ef4c342SEd Tanous } 1673f5ffd806SEd Tanous 16744c7d4d33SEd Tanous inline void handleAccountCollectionHead( 16751ef4c342SEd Tanous App& app, const crow::Request& req, 16761ef4c342SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 16771ef4c342SEd Tanous { 16783ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 167945ca1b86SEd Tanous { 168045ca1b86SEd Tanous return; 168145ca1b86SEd Tanous } 16824c7d4d33SEd Tanous asyncResp->res.addHeader( 16834c7d4d33SEd Tanous boost::beast::http::field::link, 16844c7d4d33SEd Tanous "</redfish/v1/JsonSchemas/ManagerAccountCollection.json>; rel=describedby"); 16854c7d4d33SEd Tanous } 16864c7d4d33SEd Tanous 16874c7d4d33SEd Tanous inline void handleAccountCollectionGet( 16884c7d4d33SEd Tanous App& app, const crow::Request& req, 16894c7d4d33SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 16904c7d4d33SEd Tanous { 1691afd369c6SJiaqing Zhao if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 1692afd369c6SJiaqing Zhao { 1693afd369c6SJiaqing Zhao return; 1694afd369c6SJiaqing Zhao } 16953e72c202SNinad Palsule 16963e72c202SNinad Palsule if (req.session == nullptr) 16973e72c202SNinad Palsule { 16983e72c202SNinad Palsule messages::internalError(asyncResp->res); 16993e72c202SNinad Palsule return; 17003e72c202SNinad Palsule } 17013e72c202SNinad Palsule 1702afd369c6SJiaqing Zhao asyncResp->res.addHeader( 1703afd369c6SJiaqing Zhao boost::beast::http::field::link, 1704afd369c6SJiaqing Zhao "</redfish/v1/JsonSchemas/ManagerAccountCollection.json>; rel=describedby"); 17051476687dSEd Tanous 17061476687dSEd Tanous asyncResp->res.jsonValue["@odata.id"] = 17071476687dSEd Tanous "/redfish/v1/AccountService/Accounts"; 17081ef4c342SEd Tanous asyncResp->res.jsonValue["@odata.type"] = "#ManagerAccountCollection." 17091476687dSEd Tanous "ManagerAccountCollection"; 17101476687dSEd Tanous asyncResp->res.jsonValue["Name"] = "Accounts Collection"; 17111476687dSEd Tanous asyncResp->res.jsonValue["Description"] = "BMC User Accounts"; 17120f74e643SEd Tanous 17136c51eab1SEd Tanous Privileges effectiveUserPrivileges = 17143e72c202SNinad Palsule redfish::getUserPrivileges(*req.session); 17156c51eab1SEd Tanous 1716f5e29f33SJunLin Chen std::string thisUser; 1717f5e29f33SJunLin Chen if (req.session) 1718f5e29f33SJunLin Chen { 1719f5e29f33SJunLin Chen thisUser = req.session->username; 1720f5e29f33SJunLin Chen } 17215eb468daSGeorge Liu sdbusplus::message::object_path path("/xyz/openbmc_project/user"); 17225eb468daSGeorge Liu dbus::utility::getManagedObjects( 17235eb468daSGeorge Liu "xyz.openbmc_project.User.Manager", path, 1724cef1ddfbSEd Tanous [asyncResp, thisUser, effectiveUserPrivileges]( 17255e7e2dc5SEd Tanous const boost::system::error_code& ec, 1726711ac7a9SEd Tanous const dbus::utility::ManagedObjectType& users) { 1727b9b2e0b2SEd Tanous if (ec) 1728b9b2e0b2SEd Tanous { 1729f12894f8SJason M. Bills messages::internalError(asyncResp->res); 1730b9b2e0b2SEd Tanous return; 1731b9b2e0b2SEd Tanous } 1732b9b2e0b2SEd Tanous 1733cef1ddfbSEd Tanous bool userCanSeeAllAccounts = 1734002d39b4SEd Tanous effectiveUserPrivileges.isSupersetOf({"ConfigureUsers"}); 1735cef1ddfbSEd Tanous 1736cef1ddfbSEd Tanous bool userCanSeeSelf = 1737002d39b4SEd Tanous effectiveUserPrivileges.isSupersetOf({"ConfigureSelf"}); 1738cef1ddfbSEd Tanous 1739002d39b4SEd Tanous nlohmann::json& memberArray = asyncResp->res.jsonValue["Members"]; 1740b9b2e0b2SEd Tanous memberArray = nlohmann::json::array(); 1741b9b2e0b2SEd Tanous 17429eb808c1SEd Tanous for (const auto& userpath : users) 1743b9b2e0b2SEd Tanous { 17442dfd18efSEd Tanous std::string user = userpath.first.filename(); 17452dfd18efSEd Tanous if (user.empty()) 1746b9b2e0b2SEd Tanous { 17472dfd18efSEd Tanous messages::internalError(asyncResp->res); 174862598e31SEd Tanous BMCWEB_LOG_ERROR("Invalid firmware ID"); 17492dfd18efSEd Tanous 17502dfd18efSEd Tanous return; 1751b9b2e0b2SEd Tanous } 1752f365910cSGunnar Mills 1753f365910cSGunnar Mills // As clarified by Redfish here: 1754f365910cSGunnar Mills // https://redfishforum.com/thread/281/manageraccountcollection-change-allows-account-enumeration 17556c51eab1SEd Tanous // Users without ConfigureUsers, only see their own 17566c51eab1SEd Tanous // account. Users with ConfigureUsers, see all 17576c51eab1SEd Tanous // accounts. 1758bd79bce8SPatrick Williams if (userCanSeeAllAccounts || 1759bd79bce8SPatrick Williams (thisUser == user && userCanSeeSelf)) 1760f365910cSGunnar Mills { 17611476687dSEd Tanous nlohmann::json::object_t member; 17623b32780dSEd Tanous member["@odata.id"] = boost::urls::format( 17633b32780dSEd Tanous "/redfish/v1/AccountService/Accounts/{}", user); 1764b2ba3072SPatrick Williams memberArray.emplace_back(std::move(member)); 1765b9b2e0b2SEd Tanous } 1766f365910cSGunnar Mills } 1767bd79bce8SPatrick Williams asyncResp->res.jsonValue["Members@odata.count"] = 1768bd79bce8SPatrick Williams memberArray.size(); 17695eb468daSGeorge Liu }); 17701ef4c342SEd Tanous } 17716c51eab1SEd Tanous 177297e90da3SNinad Palsule inline void processAfterCreateUser( 177397e90da3SNinad Palsule const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 177497e90da3SNinad Palsule const std::string& username, const std::string& password, 177597e90da3SNinad Palsule const boost::system::error_code& ec, sdbusplus::message_t& m) 177697e90da3SNinad Palsule { 177797e90da3SNinad Palsule if (ec) 177897e90da3SNinad Palsule { 177997e90da3SNinad Palsule userErrorMessageHandler(m.get_error(), asyncResp, username, ""); 178097e90da3SNinad Palsule return; 178197e90da3SNinad Palsule } 178297e90da3SNinad Palsule 178397e90da3SNinad Palsule if (pamUpdatePassword(username, password) != PAM_SUCCESS) 178497e90da3SNinad Palsule { 178597e90da3SNinad Palsule // At this point we have a user that's been 178697e90da3SNinad Palsule // created, but the password set 178797e90da3SNinad Palsule // failed.Something is wrong, so delete the user 178897e90da3SNinad Palsule // that we've already created 178997e90da3SNinad Palsule sdbusplus::message::object_path tempObjPath(rootUserDbusPath); 179097e90da3SNinad Palsule tempObjPath /= username; 179197e90da3SNinad Palsule const std::string userPath(tempObjPath); 179297e90da3SNinad Palsule 179397e90da3SNinad Palsule crow::connections::systemBus->async_method_call( 179497e90da3SNinad Palsule [asyncResp, password](const boost::system::error_code& ec3) { 179597e90da3SNinad Palsule if (ec3) 179697e90da3SNinad Palsule { 179797e90da3SNinad Palsule messages::internalError(asyncResp->res); 179897e90da3SNinad Palsule return; 179997e90da3SNinad Palsule } 180097e90da3SNinad Palsule 180197e90da3SNinad Palsule // If password is invalid 18029bd80831SJason M. Bills messages::propertyValueFormatError(asyncResp->res, nullptr, 180397e90da3SNinad Palsule "Password"); 180497e90da3SNinad Palsule }, 180597e90da3SNinad Palsule "xyz.openbmc_project.User.Manager", userPath, 180697e90da3SNinad Palsule "xyz.openbmc_project.Object.Delete", "Delete"); 180797e90da3SNinad Palsule 180862598e31SEd Tanous BMCWEB_LOG_ERROR("pamUpdatePassword Failed"); 180997e90da3SNinad Palsule return; 181097e90da3SNinad Palsule } 181197e90da3SNinad Palsule 181297e90da3SNinad Palsule messages::created(asyncResp->res); 181397e90da3SNinad Palsule asyncResp->res.addHeader("Location", 181497e90da3SNinad Palsule "/redfish/v1/AccountService/Accounts/" + username); 181597e90da3SNinad Palsule } 181697e90da3SNinad Palsule 181797e90da3SNinad Palsule inline void processAfterGetAllGroups( 181897e90da3SNinad Palsule const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 181997e90da3SNinad Palsule const std::string& username, const std::string& password, 1820e01d0c36SEd Tanous const std::string& roleId, bool enabled, 18219ba73934SNinad Palsule std::optional<std::vector<std::string>> accountTypes, 182297e90da3SNinad Palsule const std::vector<std::string>& allGroupsList) 182397e90da3SNinad Palsule { 18243e72c202SNinad Palsule std::vector<std::string> userGroups; 18259ba73934SNinad Palsule std::vector<std::string> accountTypeUserGroups; 18269ba73934SNinad Palsule 18279ba73934SNinad Palsule // If user specified account types then convert them to unix user groups 18289ba73934SNinad Palsule if (accountTypes) 18299ba73934SNinad Palsule { 18309ba73934SNinad Palsule if (!getUserGroupFromAccountType(asyncResp->res, *accountTypes, 18319ba73934SNinad Palsule accountTypeUserGroups)) 18329ba73934SNinad Palsule { 18339ba73934SNinad Palsule // Problem in mapping Account Types to User Groups, Error already 18349ba73934SNinad Palsule // logged. 18359ba73934SNinad Palsule return; 18369ba73934SNinad Palsule } 18379ba73934SNinad Palsule } 18389ba73934SNinad Palsule 18393e72c202SNinad Palsule for (const auto& grp : allGroupsList) 18403e72c202SNinad Palsule { 18419ba73934SNinad Palsule // If user specified the account type then only accept groups which are 18429ba73934SNinad Palsule // in the account types group list. 18439ba73934SNinad Palsule if (!accountTypeUserGroups.empty()) 18449ba73934SNinad Palsule { 18459ba73934SNinad Palsule bool found = false; 18469ba73934SNinad Palsule for (const auto& grp1 : accountTypeUserGroups) 18479ba73934SNinad Palsule { 18489ba73934SNinad Palsule if (grp == grp1) 18499ba73934SNinad Palsule { 18509ba73934SNinad Palsule found = true; 18519ba73934SNinad Palsule break; 18529ba73934SNinad Palsule } 18539ba73934SNinad Palsule } 18549ba73934SNinad Palsule if (!found) 18559ba73934SNinad Palsule { 18569ba73934SNinad Palsule continue; 18579ba73934SNinad Palsule } 18589ba73934SNinad Palsule } 18599ba73934SNinad Palsule 18603e72c202SNinad Palsule // Console access is provided to the user who is a member of 18613e72c202SNinad Palsule // hostconsole group and has a administrator role. So, set 18623e72c202SNinad Palsule // hostconsole group only for the administrator. 18639ba73934SNinad Palsule if ((grp == "hostconsole") && (roleId != "priv-admin")) 18643e72c202SNinad Palsule { 18659ba73934SNinad Palsule if (!accountTypeUserGroups.empty()) 18669ba73934SNinad Palsule { 186762598e31SEd Tanous BMCWEB_LOG_ERROR( 186862598e31SEd Tanous "Only administrator can get HostConsole access"); 18699ba73934SNinad Palsule asyncResp->res.result(boost::beast::http::status::bad_request); 18709ba73934SNinad Palsule return; 18719ba73934SNinad Palsule } 18729ba73934SNinad Palsule continue; 18739ba73934SNinad Palsule } 18743e72c202SNinad Palsule userGroups.emplace_back(grp); 18753e72c202SNinad Palsule } 18769ba73934SNinad Palsule 18779ba73934SNinad Palsule // Make sure user specified groups are valid. This is internal error because 18789ba73934SNinad Palsule // it some inconsistencies between user manager and bmcweb. 18799ba73934SNinad Palsule if (!accountTypeUserGroups.empty() && 18809ba73934SNinad Palsule accountTypeUserGroups.size() != userGroups.size()) 18819ba73934SNinad Palsule { 18829ba73934SNinad Palsule messages::internalError(asyncResp->res); 18839ba73934SNinad Palsule return; 18843e72c202SNinad Palsule } 188597e90da3SNinad Palsule crow::connections::systemBus->async_method_call( 188697e90da3SNinad Palsule [asyncResp, username, password](const boost::system::error_code& ec2, 188797e90da3SNinad Palsule sdbusplus::message_t& m) { 188897e90da3SNinad Palsule processAfterCreateUser(asyncResp, username, password, ec2, m); 188997e90da3SNinad Palsule }, 189097e90da3SNinad Palsule "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user", 18913e72c202SNinad Palsule "xyz.openbmc_project.User.Manager", "CreateUser", username, userGroups, 1892e01d0c36SEd Tanous roleId, enabled); 189397e90da3SNinad Palsule } 189497e90da3SNinad Palsule 18951ef4c342SEd Tanous inline void handleAccountCollectionPost( 18961ef4c342SEd Tanous App& app, const crow::Request& req, 18971ef4c342SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 18981ef4c342SEd Tanous { 18993ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 190045ca1b86SEd Tanous { 190145ca1b86SEd Tanous return; 190245ca1b86SEd Tanous } 19039712f8acSEd Tanous std::string username; 19049712f8acSEd Tanous std::string password; 1905e01d0c36SEd Tanous std::optional<std::string> roleIdJson; 1906e01d0c36SEd Tanous std::optional<bool> enabledJson; 19079ba73934SNinad Palsule std::optional<std::vector<std::string>> accountTypes; 1908afc474aeSMyung Bae if (!json_util::readJsonPatch( // 1909afc474aeSMyung Bae req, asyncResp->res, // 1910afc474aeSMyung Bae "AccountTypes", accountTypes, // 1911afc474aeSMyung Bae "Enabled", enabledJson, // 1912afc474aeSMyung Bae "Password", password, // 1913afc474aeSMyung Bae "RoleId", roleIdJson, // 1914afc474aeSMyung Bae "UserName", username // 1915afc474aeSMyung Bae )) 191604ae99ecSEd Tanous { 191704ae99ecSEd Tanous return; 191804ae99ecSEd Tanous } 191904ae99ecSEd Tanous 1920e01d0c36SEd Tanous std::string roleId = roleIdJson.value_or("User"); 1921e01d0c36SEd Tanous std::string priv = getPrivilegeFromRoleId(roleId); 192284e12cb7SAppaRao Puli if (priv.empty()) 192304ae99ecSEd Tanous { 1924e01d0c36SEd Tanous messages::propertyValueNotInList(asyncResp->res, roleId, "RoleId"); 192504ae99ecSEd Tanous return; 192604ae99ecSEd Tanous } 19279712f8acSEd Tanous roleId = priv; 192804ae99ecSEd Tanous 1929e01d0c36SEd Tanous bool enabled = enabledJson.value_or(true); 1930e01d0c36SEd Tanous 1931599c71d8SAyushi Smriti // Reading AllGroups property 1932deae6a78SEd Tanous dbus::utility::getProperty<std::vector<std::string>>( 1933deae6a78SEd Tanous "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user", 1934deae6a78SEd Tanous "xyz.openbmc_project.User.Manager", "AllGroups", 19359ba73934SNinad Palsule [asyncResp, username, password{std::move(password)}, roleId, enabled, 19369ba73934SNinad Palsule accountTypes](const boost::system::error_code& ec, 19371e1e598dSJonathan Doman const std::vector<std::string>& allGroupsList) { 1938599c71d8SAyushi Smriti if (ec) 1939599c71d8SAyushi Smriti { 1940a0735a4eSGunnar Mills BMCWEB_LOG_ERROR("D-Bus response error {}", ec); 1941599c71d8SAyushi Smriti messages::internalError(asyncResp->res); 1942599c71d8SAyushi Smriti return; 1943599c71d8SAyushi Smriti } 1944599c71d8SAyushi Smriti 19451e1e598dSJonathan Doman if (allGroupsList.empty()) 1946599c71d8SAyushi Smriti { 1947599c71d8SAyushi Smriti messages::internalError(asyncResp->res); 1948599c71d8SAyushi Smriti return; 1949599c71d8SAyushi Smriti } 1950599c71d8SAyushi Smriti 1951bd79bce8SPatrick Williams processAfterGetAllGroups(asyncResp, username, password, roleId, 1952bd79bce8SPatrick Williams enabled, accountTypes, allGroupsList); 19531e1e598dSJonathan Doman }); 19541ef4c342SEd Tanous } 1955b9b2e0b2SEd Tanous 19561ef4c342SEd Tanous inline void 19574c7d4d33SEd Tanous handleAccountHead(App& app, const crow::Request& req, 19586c51eab1SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 19594c7d4d33SEd Tanous const std::string& /*accountName*/) 19601ef4c342SEd Tanous { 19613ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 196245ca1b86SEd Tanous { 196345ca1b86SEd Tanous return; 196445ca1b86SEd Tanous } 19654c7d4d33SEd Tanous asyncResp->res.addHeader( 19664c7d4d33SEd Tanous boost::beast::http::field::link, 19674c7d4d33SEd Tanous "</redfish/v1/JsonSchemas/ManagerAccount/ManagerAccount.json>; rel=describedby"); 19684c7d4d33SEd Tanous } 1969afd369c6SJiaqing Zhao 19704c7d4d33SEd Tanous inline void 19714c7d4d33SEd Tanous handleAccountGet(App& app, const crow::Request& req, 19724c7d4d33SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 19734c7d4d33SEd Tanous const std::string& accountName) 19744c7d4d33SEd Tanous { 1975afd369c6SJiaqing Zhao if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 1976afd369c6SJiaqing Zhao { 1977afd369c6SJiaqing Zhao return; 1978afd369c6SJiaqing Zhao } 1979afd369c6SJiaqing Zhao asyncResp->res.addHeader( 1980afd369c6SJiaqing Zhao boost::beast::http::field::link, 1981afd369c6SJiaqing Zhao "</redfish/v1/JsonSchemas/ManagerAccount/ManagerAccount.json>; rel=describedby"); 1982afd369c6SJiaqing Zhao 198325b54dbaSEd Tanous if constexpr (BMCWEB_INSECURE_DISABLE_AUTH) 198425b54dbaSEd Tanous { 1985031514fbSJunLin Chen // If authentication is disabled, there are no user accounts 198625b54dbaSEd Tanous messages::resourceNotFound(asyncResp->res, "ManagerAccount", 198725b54dbaSEd Tanous accountName); 1988031514fbSJunLin Chen return; 198925b54dbaSEd Tanous } 1990afd369c6SJiaqing Zhao 1991031514fbSJunLin Chen if (req.session == nullptr) 1992031514fbSJunLin Chen { 1993031514fbSJunLin Chen messages::internalError(asyncResp->res); 1994031514fbSJunLin Chen return; 1995031514fbSJunLin Chen } 19966c51eab1SEd Tanous if (req.session->username != accountName) 1997b9b2e0b2SEd Tanous { 19986c51eab1SEd Tanous // At this point we've determined that the user is trying to 19991ef4c342SEd Tanous // modify a user that isn't them. We need to verify that they 20001ef4c342SEd Tanous // have permissions to modify other users, so re-run the auth 20011ef4c342SEd Tanous // check with the same permissions, minus ConfigureSelf. 20026c51eab1SEd Tanous Privileges effectiveUserPrivileges = 20033e72c202SNinad Palsule redfish::getUserPrivileges(*req.session); 20041ef4c342SEd Tanous Privileges requiredPermissionsToChangeNonSelf = {"ConfigureUsers", 20051ef4c342SEd Tanous "ConfigureManager"}; 20066c51eab1SEd Tanous if (!effectiveUserPrivileges.isSupersetOf( 20076c51eab1SEd Tanous requiredPermissionsToChangeNonSelf)) 2008900f9497SJoseph Reynolds { 200962598e31SEd Tanous BMCWEB_LOG_DEBUG("GET Account denied access"); 2010900f9497SJoseph Reynolds messages::insufficientPrivilege(asyncResp->res); 2011900f9497SJoseph Reynolds return; 2012900f9497SJoseph Reynolds } 2013900f9497SJoseph Reynolds } 2014900f9497SJoseph Reynolds 20155eb468daSGeorge Liu sdbusplus::message::object_path path("/xyz/openbmc_project/user"); 20165eb468daSGeorge Liu dbus::utility::getManagedObjects( 20175eb468daSGeorge Liu "xyz.openbmc_project.User.Manager", path, 20181ef4c342SEd Tanous [asyncResp, 20195e7e2dc5SEd Tanous accountName](const boost::system::error_code& ec, 2020711ac7a9SEd Tanous const dbus::utility::ManagedObjectType& users) { 2021b9b2e0b2SEd Tanous if (ec) 2022b9b2e0b2SEd Tanous { 2023f12894f8SJason M. Bills messages::internalError(asyncResp->res); 2024b9b2e0b2SEd Tanous return; 2025b9b2e0b2SEd Tanous } 20263544d2a7SEd Tanous const auto userIt = std::ranges::find_if( 202780f79a40SMichael Shen users, 202880f79a40SMichael Shen [accountName]( 2029b477fd44SP Dheeraj Srujan Kumar const std::pair<sdbusplus::message::object_path, 203080f79a40SMichael Shen dbus::utility::DBusInterfacesMap>& user) { 203155f79e6fSEd Tanous return accountName == user.first.filename(); 2032b477fd44SP Dheeraj Srujan Kumar }); 2033b9b2e0b2SEd Tanous 203484e12cb7SAppaRao Puli if (userIt == users.end()) 2035b9b2e0b2SEd Tanous { 2036002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "ManagerAccount", 2037002d39b4SEd Tanous accountName); 203884e12cb7SAppaRao Puli return; 203984e12cb7SAppaRao Puli } 20404e68c45bSAyushi Smriti 20411476687dSEd Tanous asyncResp->res.jsonValue["@odata.type"] = 204258345856SAbhishek Patel "#ManagerAccount.v1_7_0.ManagerAccount"; 20431476687dSEd Tanous asyncResp->res.jsonValue["Name"] = "User Account"; 20441476687dSEd Tanous asyncResp->res.jsonValue["Description"] = "User Account"; 20451476687dSEd Tanous asyncResp->res.jsonValue["Password"] = nullptr; 204658345856SAbhishek Patel asyncResp->res.jsonValue["StrictAccountTypes"] = true; 20474e68c45bSAyushi Smriti 204884e12cb7SAppaRao Puli for (const auto& interface : userIt->second) 204965b0dc32SEd Tanous { 2050002d39b4SEd Tanous if (interface.first == "xyz.openbmc_project.User.Attributes") 205165b0dc32SEd Tanous { 2052b437a535SAsmitha Karunanithi const bool* userEnabled = nullptr; 2053b437a535SAsmitha Karunanithi const bool* userLocked = nullptr; 2054b437a535SAsmitha Karunanithi const std::string* userPrivPtr = nullptr; 2055b437a535SAsmitha Karunanithi const bool* userPasswordExpired = nullptr; 2056b437a535SAsmitha Karunanithi const std::vector<std::string>* userGroups = nullptr; 2057b437a535SAsmitha Karunanithi 2058b437a535SAsmitha Karunanithi const bool success = sdbusplus::unpackPropertiesNoThrow( 2059b437a535SAsmitha Karunanithi dbus_utils::UnpackErrorPrinter(), interface.second, 2060b437a535SAsmitha Karunanithi "UserEnabled", userEnabled, 2061b437a535SAsmitha Karunanithi "UserLockedForFailedAttempt", userLocked, 2062b437a535SAsmitha Karunanithi "UserPrivilege", userPrivPtr, "UserPasswordExpired", 2063b437a535SAsmitha Karunanithi userPasswordExpired, "UserGroups", userGroups); 2064b437a535SAsmitha Karunanithi if (!success) 206565b0dc32SEd Tanous { 2066b437a535SAsmitha Karunanithi messages::internalError(asyncResp->res); 2067b437a535SAsmitha Karunanithi return; 2068b437a535SAsmitha Karunanithi } 206965b0dc32SEd Tanous if (userEnabled == nullptr) 207065b0dc32SEd Tanous { 207162598e31SEd Tanous BMCWEB_LOG_ERROR("UserEnabled wasn't a bool"); 207284e12cb7SAppaRao Puli messages::internalError(asyncResp->res); 207384e12cb7SAppaRao Puli return; 207465b0dc32SEd Tanous } 2075002d39b4SEd Tanous asyncResp->res.jsonValue["Enabled"] = *userEnabled; 2076b437a535SAsmitha Karunanithi 207765b0dc32SEd Tanous if (userLocked == nullptr) 207865b0dc32SEd Tanous { 207962598e31SEd Tanous BMCWEB_LOG_ERROR("UserLockedForF" 208084e12cb7SAppaRao Puli "ailedAttempt " 208162598e31SEd Tanous "wasn't a bool"); 208284e12cb7SAppaRao Puli messages::internalError(asyncResp->res); 208384e12cb7SAppaRao Puli return; 208465b0dc32SEd Tanous } 2085002d39b4SEd Tanous asyncResp->res.jsonValue["Locked"] = *userLocked; 208620fa6a2cSEd Tanous nlohmann::json::array_t allowed; 208720fa6a2cSEd Tanous // can only unlock accounts 208820fa6a2cSEd Tanous allowed.emplace_back("false"); 2089b437a535SAsmitha Karunanithi asyncResp->res.jsonValue["Locked@Redfish.AllowableValues"] = 209020fa6a2cSEd Tanous std::move(allowed); 2091b437a535SAsmitha Karunanithi 209254fc587aSNagaraju Goruganti if (userPrivPtr == nullptr) 209384e12cb7SAppaRao Puli { 209462598e31SEd Tanous BMCWEB_LOG_ERROR("UserPrivilege wasn't a " 209562598e31SEd Tanous "string"); 209684e12cb7SAppaRao Puli messages::internalError(asyncResp->res); 209784e12cb7SAppaRao Puli return; 209884e12cb7SAppaRao Puli } 2099b437a535SAsmitha Karunanithi std::string role = getRoleIdFromPrivilege(*userPrivPtr); 210054fc587aSNagaraju Goruganti if (role.empty()) 210184e12cb7SAppaRao Puli { 210262598e31SEd Tanous BMCWEB_LOG_ERROR("Invalid user role"); 210384e12cb7SAppaRao Puli messages::internalError(asyncResp->res); 210484e12cb7SAppaRao Puli return; 210584e12cb7SAppaRao Puli } 210654fc587aSNagaraju Goruganti asyncResp->res.jsonValue["RoleId"] = role; 210784e12cb7SAppaRao Puli 21081476687dSEd Tanous nlohmann::json& roleEntry = 2109002d39b4SEd Tanous asyncResp->res.jsonValue["Links"]["Role"]; 21103b32780dSEd Tanous roleEntry["@odata.id"] = boost::urls::format( 21113b32780dSEd Tanous "/redfish/v1/AccountService/Roles/{}", role); 2112b437a535SAsmitha Karunanithi 21133bf4e632SJoseph Reynolds if (userPasswordExpired == nullptr) 21143bf4e632SJoseph Reynolds { 2115b437a535SAsmitha Karunanithi BMCWEB_LOG_ERROR("UserPasswordExpired wasn't a bool"); 21163bf4e632SJoseph Reynolds messages::internalError(asyncResp->res); 21173bf4e632SJoseph Reynolds return; 21183bf4e632SJoseph Reynolds } 2119002d39b4SEd Tanous asyncResp->res.jsonValue["PasswordChangeRequired"] = 21203bf4e632SJoseph Reynolds *userPasswordExpired; 2121b437a535SAsmitha Karunanithi 2122c7229815SAbhishek Patel if (userGroups == nullptr) 2123c7229815SAbhishek Patel { 2124b437a535SAsmitha Karunanithi BMCWEB_LOG_ERROR("userGroups wasn't a string vector"); 2125c7229815SAbhishek Patel messages::internalError(asyncResp->res); 2126c7229815SAbhishek Patel return; 2127c7229815SAbhishek Patel } 2128b437a535SAsmitha Karunanithi if (!translateUserGroup(*userGroups, asyncResp->res)) 2129c7229815SAbhishek Patel { 213062598e31SEd Tanous BMCWEB_LOG_ERROR("userGroups mapping failed"); 2131c7229815SAbhishek Patel messages::internalError(asyncResp->res); 2132c7229815SAbhishek Patel return; 2133c7229815SAbhishek Patel } 2134c7229815SAbhishek Patel } 213565b0dc32SEd Tanous } 213665b0dc32SEd Tanous 21373b32780dSEd Tanous asyncResp->res.jsonValue["@odata.id"] = boost::urls::format( 21383b32780dSEd Tanous "/redfish/v1/AccountService/Accounts/{}", accountName); 2139b9b2e0b2SEd Tanous asyncResp->res.jsonValue["Id"] = accountName; 2140b9b2e0b2SEd Tanous asyncResp->res.jsonValue["UserName"] = accountName; 21415eb468daSGeorge Liu }); 21421ef4c342SEd Tanous } 2143a840879dSEd Tanous 21441ef4c342SEd Tanous inline void 214520fc307fSGunnar Mills handleAccountDelete(App& app, const crow::Request& req, 21466c51eab1SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 21471ef4c342SEd Tanous const std::string& username) 21481ef4c342SEd Tanous { 21493ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 215045ca1b86SEd Tanous { 215145ca1b86SEd Tanous return; 215245ca1b86SEd Tanous } 21531ef4c342SEd Tanous 215425b54dbaSEd Tanous if constexpr (BMCWEB_INSECURE_DISABLE_AUTH) 215525b54dbaSEd Tanous { 2156031514fbSJunLin Chen // If authentication is disabled, there are no user accounts 2157d8a5d5d8SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "ManagerAccount", username); 2158031514fbSJunLin Chen return; 215925b54dbaSEd Tanous } 21601ef4c342SEd Tanous sdbusplus::message::object_path tempObjPath(rootUserDbusPath); 21611ef4c342SEd Tanous tempObjPath /= username; 21621ef4c342SEd Tanous const std::string userPath(tempObjPath); 21631ef4c342SEd Tanous 21641ef4c342SEd Tanous crow::connections::systemBus->async_method_call( 21655e7e2dc5SEd Tanous [asyncResp, username](const boost::system::error_code& ec) { 21661ef4c342SEd Tanous if (ec) 21671ef4c342SEd Tanous { 2168d8a5d5d8SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "ManagerAccount", 21691ef4c342SEd Tanous username); 21701ef4c342SEd Tanous return; 21711ef4c342SEd Tanous } 21721ef4c342SEd Tanous 21731ef4c342SEd Tanous messages::accountRemoved(asyncResp->res); 21741ef4c342SEd Tanous }, 21751ef4c342SEd Tanous "xyz.openbmc_project.User.Manager", userPath, 21761ef4c342SEd Tanous "xyz.openbmc_project.Object.Delete", "Delete"); 21771ef4c342SEd Tanous } 21781ef4c342SEd Tanous 21791ef4c342SEd Tanous inline void 21801ef4c342SEd Tanous handleAccountPatch(App& app, const crow::Request& req, 21811ef4c342SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 21821ef4c342SEd Tanous const std::string& username) 21831ef4c342SEd Tanous { 21841ef4c342SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 21851ef4c342SEd Tanous { 21861ef4c342SEd Tanous return; 21871ef4c342SEd Tanous } 218825b54dbaSEd Tanous if constexpr (BMCWEB_INSECURE_DISABLE_AUTH) 218925b54dbaSEd Tanous { 21901ef4c342SEd Tanous // If authentication is disabled, there are no user accounts 2191d8a5d5d8SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "ManagerAccount", username); 21921ef4c342SEd Tanous return; 219325b54dbaSEd Tanous } 2194a24526dcSEd Tanous std::optional<std::string> newUserName; 2195a24526dcSEd Tanous std::optional<std::string> password; 2196a24526dcSEd Tanous std::optional<bool> enabled; 2197a24526dcSEd Tanous std::optional<std::string> roleId; 219824c8542dSRatan Gupta std::optional<bool> locked; 219958345856SAbhishek Patel std::optional<std::vector<std::string>> accountTypes; 220058345856SAbhishek Patel 2201031514fbSJunLin Chen if (req.session == nullptr) 2202031514fbSJunLin Chen { 2203031514fbSJunLin Chen messages::internalError(asyncResp->res); 2204031514fbSJunLin Chen return; 2205031514fbSJunLin Chen } 2206031514fbSJunLin Chen 22072b9c1dfeSEd Tanous bool userSelf = (username == req.session->username); 22082b9c1dfeSEd Tanous 2209e9cc5172SEd Tanous Privileges effectiveUserPrivileges = 22103e72c202SNinad Palsule redfish::getUserPrivileges(*req.session); 2211e9cc5172SEd Tanous Privileges configureUsers = {"ConfigureUsers"}; 2212e9cc5172SEd Tanous bool userHasConfigureUsers = 2213e9cc5172SEd Tanous effectiveUserPrivileges.isSupersetOf(configureUsers); 2214e9cc5172SEd Tanous if (userHasConfigureUsers) 2215e9cc5172SEd Tanous { 2216e9cc5172SEd Tanous // Users with ConfigureUsers can modify for all users 2217afc474aeSMyung Bae if (!json_util::readJsonPatch( // 2218afc474aeSMyung Bae req, asyncResp->res, // 2219afc474aeSMyung Bae "AccountTypes", accountTypes, // 2220afc474aeSMyung Bae "Enabled", enabled, // 2221afc474aeSMyung Bae "Locked", locked, // 2222afc474aeSMyung Bae "Password", password, // 2223afc474aeSMyung Bae "RoleId", roleId, // 2224afc474aeSMyung Bae "UserName", newUserName // 2225afc474aeSMyung Bae )) 2226a840879dSEd Tanous { 2227a840879dSEd Tanous return; 2228a840879dSEd Tanous } 2229e9cc5172SEd Tanous } 2230e9cc5172SEd Tanous else 2231900f9497SJoseph Reynolds { 2232e9cc5172SEd Tanous // ConfigureSelf accounts can only modify their own account 223358345856SAbhishek Patel if (!userSelf) 2234900f9497SJoseph Reynolds { 2235900f9497SJoseph Reynolds messages::insufficientPrivilege(asyncResp->res); 2236900f9497SJoseph Reynolds return; 2237900f9497SJoseph Reynolds } 2238031514fbSJunLin Chen 2239e9cc5172SEd Tanous // ConfigureSelf accounts can only modify their password 22401ef4c342SEd Tanous if (!json_util::readJsonPatch(req, asyncResp->res, "Password", 22411ef4c342SEd Tanous password)) 2242e9cc5172SEd Tanous { 2243e9cc5172SEd Tanous return; 2244e9cc5172SEd Tanous } 2245900f9497SJoseph Reynolds } 2246900f9497SJoseph Reynolds 224766b5ca76Sjayaprakash Mutyala // if user name is not provided in the patch method or if it 22486c51eab1SEd Tanous // matches the user name in the URI, then we are treating it as 22496c51eab1SEd Tanous // updating user properties other then username. If username 22506c51eab1SEd Tanous // provided doesn't match the URI, then we are treating this as 22516c51eab1SEd Tanous // user rename request. 225266b5ca76Sjayaprakash Mutyala if (!newUserName || (newUserName.value() == username)) 2253a840879dSEd Tanous { 22541ef4c342SEd Tanous updateUserProperties(asyncResp, username, password, enabled, roleId, 2255e518ef32SRavi Teja locked, accountTypes, userSelf, req.session); 225684e12cb7SAppaRao Puli return; 225784e12cb7SAppaRao Puli } 225884e12cb7SAppaRao Puli crow::connections::systemBus->async_method_call( 22596c51eab1SEd Tanous [asyncResp, username, password(std::move(password)), 22601ef4c342SEd Tanous roleId(std::move(roleId)), enabled, newUser{std::string(*newUserName)}, 2261e518ef32SRavi Teja locked, userSelf, req, accountTypes(std::move(accountTypes))]( 2262e81de512SEd Tanous const boost::system::error_code& ec, sdbusplus::message_t& m) { 226384e12cb7SAppaRao Puli if (ec) 226484e12cb7SAppaRao Puli { 2265002d39b4SEd Tanous userErrorMessageHandler(m.get_error(), asyncResp, newUser, 2266002d39b4SEd Tanous username); 2267a840879dSEd Tanous return; 2268a840879dSEd Tanous } 2269a840879dSEd Tanous 2270002d39b4SEd Tanous updateUserProperties(asyncResp, newUser, password, enabled, roleId, 2271e518ef32SRavi Teja locked, accountTypes, userSelf, req.session); 227284e12cb7SAppaRao Puli }, 22731ef4c342SEd Tanous "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user", 227484e12cb7SAppaRao Puli "xyz.openbmc_project.User.Manager", "RenameUser", username, 227584e12cb7SAppaRao Puli *newUserName); 22761ef4c342SEd Tanous } 22771ef4c342SEd Tanous 22781ef4c342SEd Tanous inline void requestAccountServiceRoutes(App& app) 22791ef4c342SEd Tanous { 22801ef4c342SEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/AccountService/") 22814c7d4d33SEd Tanous .privileges(redfish::privileges::headAccountService) 22824c7d4d33SEd Tanous .methods(boost::beast::http::verb::head)( 22834c7d4d33SEd Tanous std::bind_front(handleAccountServiceHead, std::ref(app))); 22844c7d4d33SEd Tanous 22854c7d4d33SEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/AccountService/") 22861ef4c342SEd Tanous .privileges(redfish::privileges::getAccountService) 22871ef4c342SEd Tanous .methods(boost::beast::http::verb::get)( 22881ef4c342SEd Tanous std::bind_front(handleAccountServiceGet, std::ref(app))); 22891ef4c342SEd Tanous 22901ef4c342SEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/AccountService/") 22911ef4c342SEd Tanous .privileges(redfish::privileges::patchAccountService) 22921ef4c342SEd Tanous .methods(boost::beast::http::verb::patch)( 22931ef4c342SEd Tanous std::bind_front(handleAccountServicePatch, std::ref(app))); 22941ef4c342SEd Tanous 22951aa375b8SEd Tanous BMCWEB_ROUTE( 22961aa375b8SEd Tanous app, 2297e9f12014SEd Tanous "/redfish/v1/AccountService/MultiFactorAuth/ClientCertificate/Certificates/") 22981aa375b8SEd Tanous .privileges(redfish::privileges::headCertificateCollection) 22991aa375b8SEd Tanous .methods(boost::beast::http::verb::head)(std::bind_front( 23001aa375b8SEd Tanous handleAccountServiceClientCertificatesHead, std::ref(app))); 23011aa375b8SEd Tanous 23021aa375b8SEd Tanous BMCWEB_ROUTE( 23031aa375b8SEd Tanous app, 2304e9f12014SEd Tanous "/redfish/v1/AccountService/MultiFactorAuth/ClientCertificate/Certificates/") 23051aa375b8SEd Tanous .privileges(redfish::privileges::getCertificateCollection) 23061aa375b8SEd Tanous .methods(boost::beast::http::verb::get)(std::bind_front( 23071aa375b8SEd Tanous handleAccountServiceClientCertificatesGet, std::ref(app))); 23081aa375b8SEd Tanous 23091aa375b8SEd Tanous BMCWEB_ROUTE( 23101aa375b8SEd Tanous app, 2311e9f12014SEd Tanous "/redfish/v1/AccountService/MultiFactorAuth/ClientCertificate/Certificates/<str>/") 23121aa375b8SEd Tanous .privileges(redfish::privileges::headCertificate) 23131aa375b8SEd Tanous .methods(boost::beast::http::verb::head)(std::bind_front( 23141aa375b8SEd Tanous handleAccountServiceClientCertificatesInstanceHead, std::ref(app))); 23151aa375b8SEd Tanous 23161aa375b8SEd Tanous BMCWEB_ROUTE( 23171aa375b8SEd Tanous app, 23181aa375b8SEd Tanous "/redfish/v1/AccountService/MultiFactorAuth/ClientCertificate/Certificates/<str>/") 23191aa375b8SEd Tanous .privileges(redfish::privileges::getCertificate) 23201aa375b8SEd Tanous .methods(boost::beast::http::verb::get)(std::bind_front( 23211aa375b8SEd Tanous handleAccountServiceClientCertificatesInstanceGet, std::ref(app))); 23221aa375b8SEd Tanous 23231ef4c342SEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/") 23244c7d4d33SEd Tanous .privileges(redfish::privileges::headManagerAccountCollection) 23254c7d4d33SEd Tanous .methods(boost::beast::http::verb::head)( 23264c7d4d33SEd Tanous std::bind_front(handleAccountCollectionHead, std::ref(app))); 23274c7d4d33SEd Tanous 23284c7d4d33SEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/") 23291ef4c342SEd Tanous .privileges(redfish::privileges::getManagerAccountCollection) 23301ef4c342SEd Tanous .methods(boost::beast::http::verb::get)( 23311ef4c342SEd Tanous std::bind_front(handleAccountCollectionGet, std::ref(app))); 23321ef4c342SEd Tanous 23331ef4c342SEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/") 23341ef4c342SEd Tanous .privileges(redfish::privileges::postManagerAccountCollection) 23351ef4c342SEd Tanous .methods(boost::beast::http::verb::post)( 23361ef4c342SEd Tanous std::bind_front(handleAccountCollectionPost, std::ref(app))); 23371ef4c342SEd Tanous 23381ef4c342SEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/<str>/") 23394c7d4d33SEd Tanous .privileges(redfish::privileges::headManagerAccount) 23404c7d4d33SEd Tanous .methods(boost::beast::http::verb::head)( 23414c7d4d33SEd Tanous std::bind_front(handleAccountHead, std::ref(app))); 23424c7d4d33SEd Tanous 23434c7d4d33SEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/<str>/") 23441ef4c342SEd Tanous .privileges(redfish::privileges::getManagerAccount) 23451ef4c342SEd Tanous .methods(boost::beast::http::verb::get)( 23461ef4c342SEd Tanous std::bind_front(handleAccountGet, std::ref(app))); 23471ef4c342SEd Tanous 23481ef4c342SEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/<str>/") 23491ef4c342SEd Tanous // TODO this privilege should be using the generated endpoints, but 23501ef4c342SEd Tanous // because of the special handling of ConfigureSelf, it's not able to 23511ef4c342SEd Tanous // yet 23521ef4c342SEd Tanous .privileges({{"ConfigureUsers"}, {"ConfigureSelf"}}) 23531ef4c342SEd Tanous .methods(boost::beast::http::verb::patch)( 23541ef4c342SEd Tanous std::bind_front(handleAccountPatch, std::ref(app))); 235584e12cb7SAppaRao Puli 23566c51eab1SEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/<str>/") 2357ed398213SEd Tanous .privileges(redfish::privileges::deleteManagerAccount) 23586c51eab1SEd Tanous .methods(boost::beast::http::verb::delete_)( 235920fc307fSGunnar Mills std::bind_front(handleAccountDelete, std::ref(app))); 236006e086d9SEd Tanous } 236188d16c9aSLewanczyk, Dawid 236288d16c9aSLewanczyk, Dawid } // namespace redfish 2363