188d16c9aSLewanczyk, Dawid /* 26be832e2SEd Tanous Copyright (c) 2018 Intel Corporation 36be832e2SEd Tanous 46be832e2SEd Tanous Licensed under the Apache License, Version 2.0 (the "License"); 56be832e2SEd Tanous you may not use this file except in compliance with the License. 66be832e2SEd Tanous You may obtain a copy of the License at 76be832e2SEd Tanous 86be832e2SEd Tanous http://www.apache.org/licenses/LICENSE-2.0 96be832e2SEd Tanous 106be832e2SEd Tanous Unless required by applicable law or agreed to in writing, software 116be832e2SEd Tanous distributed under the License is distributed on an "AS IS" BASIS, 126be832e2SEd Tanous WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 136be832e2SEd Tanous See the License for the specific language governing permissions and 146be832e2SEd Tanous limitations under the License. 1588d16c9aSLewanczyk, Dawid */ 1688d16c9aSLewanczyk, Dawid #pragma once 1788d16c9aSLewanczyk, Dawid 183ccb3adbSEd Tanous #include "app.hpp" 19a0735a4eSGunnar Mills #include "boost_formatters.hpp" 201aa375b8SEd Tanous #include "certificate_service.hpp" 213ccb3adbSEd Tanous #include "dbus_utility.hpp" 223ccb3adbSEd Tanous #include "error_messages.hpp" 230ec8b83dSEd Tanous #include "generated/enums/account_service.hpp" 243ccb3adbSEd Tanous #include "persistent_data.hpp" 253ccb3adbSEd Tanous #include "query.hpp" 260ec8b83dSEd Tanous #include "registries/privilege_registry.hpp" 273281bcf1SEd Tanous #include "sessions.hpp" 281aa375b8SEd Tanous #include "utils/collection.hpp" 293ccb3adbSEd Tanous #include "utils/dbus_utils.hpp" 303ccb3adbSEd Tanous #include "utils/json_utils.hpp" 310ec8b83dSEd Tanous 321aa375b8SEd Tanous #include <boost/url/format.hpp> 331aa375b8SEd Tanous #include <boost/url/url.hpp> 341e1e598dSJonathan Doman #include <sdbusplus/asio/property.hpp> 35d1bde9e5SKrzysztof Grobelny #include <sdbusplus/unpack_properties.hpp> 361214b7e7SGunnar Mills 372b73119cSGeorge Liu #include <array> 381aa375b8SEd Tanous #include <memory> 39c7229815SAbhishek Patel #include <optional> 403544d2a7SEd Tanous #include <ranges> 41c7229815SAbhishek Patel #include <string> 422b73119cSGeorge Liu #include <string_view> 4320fa6a2cSEd Tanous #include <utility> 44c7229815SAbhishek Patel #include <vector> 45c7229815SAbhishek Patel 461abe55efSEd Tanous namespace redfish 471abe55efSEd Tanous { 4888d16c9aSLewanczyk, Dawid 4923a21a1cSEd Tanous constexpr const char* ldapConfigObjectName = 506973a582SRatan Gupta "/xyz/openbmc_project/user/ldap/openldap"; 512c70f800SEd Tanous constexpr const char* adConfigObject = 52ab828d7cSRatan Gupta "/xyz/openbmc_project/user/ldap/active_directory"; 53ab828d7cSRatan Gupta 54b477fd44SP Dheeraj Srujan Kumar constexpr const char* rootUserDbusPath = "/xyz/openbmc_project/user/"; 556973a582SRatan Gupta constexpr const char* ldapRootObject = "/xyz/openbmc_project/user/ldap"; 566973a582SRatan Gupta constexpr const char* ldapDbusService = "xyz.openbmc_project.Ldap.Config"; 576973a582SRatan Gupta constexpr const char* ldapConfigInterface = 586973a582SRatan Gupta "xyz.openbmc_project.User.Ldap.Config"; 596973a582SRatan Gupta constexpr const char* ldapCreateInterface = 606973a582SRatan Gupta "xyz.openbmc_project.User.Ldap.Create"; 616973a582SRatan Gupta constexpr const char* ldapEnableInterface = "xyz.openbmc_project.Object.Enable"; 6206785244SRatan Gupta constexpr const char* ldapPrivMapperInterface = 6306785244SRatan Gupta "xyz.openbmc_project.User.PrivilegeMapper"; 646973a582SRatan Gupta 6554fc587aSNagaraju Goruganti struct LDAPRoleMapData 6654fc587aSNagaraju Goruganti { 6754fc587aSNagaraju Goruganti std::string groupName; 6854fc587aSNagaraju Goruganti std::string privilege; 6954fc587aSNagaraju Goruganti }; 7054fc587aSNagaraju Goruganti 716973a582SRatan Gupta struct LDAPConfigData 726973a582SRatan Gupta { 7347f2934cSEd Tanous std::string uri; 7447f2934cSEd Tanous std::string bindDN; 7547f2934cSEd Tanous std::string baseDN; 7647f2934cSEd Tanous std::string searchScope; 7747f2934cSEd Tanous std::string serverType; 786973a582SRatan Gupta bool serviceEnabled = false; 7947f2934cSEd Tanous std::string userNameAttribute; 8047f2934cSEd Tanous std::string groupAttribute; 8154fc587aSNagaraju Goruganti std::vector<std::pair<std::string, LDAPRoleMapData>> groupRoleList; 826973a582SRatan Gupta }; 836973a582SRatan Gupta 8454fc587aSNagaraju Goruganti inline std::string getRoleIdFromPrivilege(std::string_view role) 8584e12cb7SAppaRao Puli { 8684e12cb7SAppaRao Puli if (role == "priv-admin") 8784e12cb7SAppaRao Puli { 8884e12cb7SAppaRao Puli return "Administrator"; 8984e12cb7SAppaRao Puli } 903174e4dfSEd Tanous if (role == "priv-user") 9184e12cb7SAppaRao Puli { 92c80fee55SAppaRao Puli return "ReadOnly"; 9384e12cb7SAppaRao Puli } 943174e4dfSEd Tanous if (role == "priv-operator") 9584e12cb7SAppaRao Puli { 9684e12cb7SAppaRao Puli return "Operator"; 9784e12cb7SAppaRao Puli } 9884e12cb7SAppaRao Puli return ""; 9984e12cb7SAppaRao Puli } 10054fc587aSNagaraju Goruganti inline std::string getPrivilegeFromRoleId(std::string_view role) 10184e12cb7SAppaRao Puli { 10284e12cb7SAppaRao Puli if (role == "Administrator") 10384e12cb7SAppaRao Puli { 10484e12cb7SAppaRao Puli return "priv-admin"; 10584e12cb7SAppaRao Puli } 1063174e4dfSEd Tanous if (role == "ReadOnly") 10784e12cb7SAppaRao Puli { 10884e12cb7SAppaRao Puli return "priv-user"; 10984e12cb7SAppaRao Puli } 1103174e4dfSEd Tanous if (role == "Operator") 11184e12cb7SAppaRao Puli { 11284e12cb7SAppaRao Puli return "priv-operator"; 11384e12cb7SAppaRao Puli } 11484e12cb7SAppaRao Puli return ""; 11584e12cb7SAppaRao Puli } 116b9b2e0b2SEd Tanous 117c7229815SAbhishek Patel /** 118c7229815SAbhishek Patel * @brief Maps user group names retrieved from D-Bus object to 119c7229815SAbhishek Patel * Account Types. 120c7229815SAbhishek Patel * 121c7229815SAbhishek Patel * @param[in] userGroups List of User groups 122c7229815SAbhishek Patel * @param[out] res AccountTypes populated 123c7229815SAbhishek Patel * 124c7229815SAbhishek Patel * @return true in case of success, false if UserGroups contains 125c7229815SAbhishek Patel * invalid group name(s). 126c7229815SAbhishek Patel */ 127c7229815SAbhishek Patel inline bool translateUserGroup(const std::vector<std::string>& userGroups, 128c7229815SAbhishek Patel crow::Response& res) 129c7229815SAbhishek Patel { 130c7229815SAbhishek Patel std::vector<std::string> accountTypes; 131c7229815SAbhishek Patel for (const auto& userGroup : userGroups) 132c7229815SAbhishek Patel { 133c7229815SAbhishek Patel if (userGroup == "redfish") 134c7229815SAbhishek Patel { 135c7229815SAbhishek Patel accountTypes.emplace_back("Redfish"); 136c7229815SAbhishek Patel accountTypes.emplace_back("WebUI"); 137c7229815SAbhishek Patel } 138c7229815SAbhishek Patel else if (userGroup == "ipmi") 139c7229815SAbhishek Patel { 140c7229815SAbhishek Patel accountTypes.emplace_back("IPMI"); 141c7229815SAbhishek Patel } 142c7229815SAbhishek Patel else if (userGroup == "ssh") 143c7229815SAbhishek Patel { 144c7229815SAbhishek Patel accountTypes.emplace_back("ManagerConsole"); 145c7229815SAbhishek Patel } 1463e72c202SNinad Palsule else if (userGroup == "hostconsole") 1473e72c202SNinad Palsule { 1483e72c202SNinad Palsule // The hostconsole group controls who can access the host console 1493e72c202SNinad Palsule // port via ssh and websocket. 1503e72c202SNinad Palsule accountTypes.emplace_back("HostConsole"); 1513e72c202SNinad Palsule } 152c7229815SAbhishek Patel else if (userGroup == "web") 153c7229815SAbhishek Patel { 154c7229815SAbhishek Patel // 'web' is one of the valid groups in the UserGroups property of 155c7229815SAbhishek Patel // the user account in the D-Bus object. This group is currently not 156c7229815SAbhishek Patel // doing anything, and is considered to be equivalent to 'redfish'. 157c7229815SAbhishek Patel // 'redfish' user group is mapped to 'Redfish'and 'WebUI' 158c7229815SAbhishek Patel // AccountTypes, so do nothing here... 159c7229815SAbhishek Patel } 160c7229815SAbhishek Patel else 161c7229815SAbhishek Patel { 1628ece0e45SEd Tanous // Invalid user group name. Caller throws an exception. 163c7229815SAbhishek Patel return false; 164c7229815SAbhishek Patel } 165c7229815SAbhishek Patel } 166c7229815SAbhishek Patel 167c7229815SAbhishek Patel res.jsonValue["AccountTypes"] = std::move(accountTypes); 168c7229815SAbhishek Patel return true; 169c7229815SAbhishek Patel } 170c7229815SAbhishek Patel 17158345856SAbhishek Patel /** 17258345856SAbhishek Patel * @brief Builds User Groups from the Account Types 17358345856SAbhishek Patel * 17458345856SAbhishek Patel * @param[in] asyncResp Async Response 17558345856SAbhishek Patel * @param[in] accountTypes List of Account Types 17658345856SAbhishek Patel * @param[out] userGroups List of User Groups mapped from Account Types 17758345856SAbhishek Patel * 17858345856SAbhishek Patel * @return true if Account Types mapped to User Groups, false otherwise. 17958345856SAbhishek Patel */ 180bd79bce8SPatrick Williams inline bool getUserGroupFromAccountType( 181bd79bce8SPatrick Williams crow::Response& res, const std::vector<std::string>& accountTypes, 18258345856SAbhishek Patel std::vector<std::string>& userGroups) 18358345856SAbhishek Patel { 18458345856SAbhishek Patel // Need both Redfish and WebUI Account Types to map to 'redfish' User Group 18558345856SAbhishek Patel bool redfishType = false; 18658345856SAbhishek Patel bool webUIType = false; 18758345856SAbhishek Patel 18858345856SAbhishek Patel for (const auto& accountType : accountTypes) 18958345856SAbhishek Patel { 19058345856SAbhishek Patel if (accountType == "Redfish") 19158345856SAbhishek Patel { 19258345856SAbhishek Patel redfishType = true; 19358345856SAbhishek Patel } 19458345856SAbhishek Patel else if (accountType == "WebUI") 19558345856SAbhishek Patel { 19658345856SAbhishek Patel webUIType = true; 19758345856SAbhishek Patel } 19858345856SAbhishek Patel else if (accountType == "IPMI") 19958345856SAbhishek Patel { 20058345856SAbhishek Patel userGroups.emplace_back("ipmi"); 20158345856SAbhishek Patel } 20258345856SAbhishek Patel else if (accountType == "HostConsole") 20358345856SAbhishek Patel { 20458345856SAbhishek Patel userGroups.emplace_back("hostconsole"); 20558345856SAbhishek Patel } 20658345856SAbhishek Patel else if (accountType == "ManagerConsole") 20758345856SAbhishek Patel { 20858345856SAbhishek Patel userGroups.emplace_back("ssh"); 20958345856SAbhishek Patel } 21058345856SAbhishek Patel else 21158345856SAbhishek Patel { 21258345856SAbhishek Patel // Invalid Account Type 21358345856SAbhishek Patel messages::propertyValueNotInList(res, "AccountTypes", accountType); 21458345856SAbhishek Patel return false; 21558345856SAbhishek Patel } 21658345856SAbhishek Patel } 21758345856SAbhishek Patel 21858345856SAbhishek Patel // Both Redfish and WebUI Account Types are needed to PATCH 21958345856SAbhishek Patel if (redfishType ^ webUIType) 22058345856SAbhishek Patel { 22162598e31SEd Tanous BMCWEB_LOG_ERROR( 22262598e31SEd Tanous "Missing Redfish or WebUI Account Type to set redfish User Group"); 22358345856SAbhishek Patel messages::strictAccountTypes(res, "AccountTypes"); 22458345856SAbhishek Patel return false; 22558345856SAbhishek Patel } 22658345856SAbhishek Patel 22758345856SAbhishek Patel if (redfishType && webUIType) 22858345856SAbhishek Patel { 22958345856SAbhishek Patel userGroups.emplace_back("redfish"); 23058345856SAbhishek Patel } 23158345856SAbhishek Patel 23258345856SAbhishek Patel return true; 23358345856SAbhishek Patel } 23458345856SAbhishek Patel 23558345856SAbhishek Patel /** 23658345856SAbhishek Patel * @brief Sets UserGroups property of the user based on the Account Types 23758345856SAbhishek Patel * 23858345856SAbhishek Patel * @param[in] accountTypes List of User Account Types 23958345856SAbhishek Patel * @param[in] asyncResp Async Response 24058345856SAbhishek Patel * @param[in] dbusObjectPath D-Bus Object Path 24158345856SAbhishek Patel * @param[in] userSelf true if User is updating OWN Account Types 24258345856SAbhishek Patel */ 24358345856SAbhishek Patel inline void 24458345856SAbhishek Patel patchAccountTypes(const std::vector<std::string>& accountTypes, 24558345856SAbhishek Patel const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 24658345856SAbhishek Patel const std::string& dbusObjectPath, bool userSelf) 24758345856SAbhishek Patel { 24858345856SAbhishek Patel // Check if User is disabling own Redfish Account Type 24958345856SAbhishek Patel if (userSelf && 25058345856SAbhishek Patel (accountTypes.cend() == 25158345856SAbhishek Patel std::find(accountTypes.cbegin(), accountTypes.cend(), "Redfish"))) 25258345856SAbhishek Patel { 25362598e31SEd Tanous BMCWEB_LOG_ERROR( 25462598e31SEd Tanous "User disabling OWN Redfish Account Type is not allowed"); 25558345856SAbhishek Patel messages::strictAccountTypes(asyncResp->res, "AccountTypes"); 25658345856SAbhishek Patel return; 25758345856SAbhishek Patel } 25858345856SAbhishek Patel 25958345856SAbhishek Patel std::vector<std::string> updatedUserGroups; 26058345856SAbhishek Patel if (!getUserGroupFromAccountType(asyncResp->res, accountTypes, 26158345856SAbhishek Patel updatedUserGroups)) 26258345856SAbhishek Patel { 26358345856SAbhishek Patel // Problem in mapping Account Types to User Groups, Error already 26458345856SAbhishek Patel // logged. 26558345856SAbhishek Patel return; 26658345856SAbhishek Patel } 267e93abac6SGinu George setDbusProperty(asyncResp, "AccountTypes", 268e93abac6SGinu George "xyz.openbmc_project.User.Manager", dbusObjectPath, 269e93abac6SGinu George "xyz.openbmc_project.User.Attributes", "UserGroups", 270e93abac6SGinu George updatedUserGroups); 27158345856SAbhishek Patel } 27258345856SAbhishek Patel 2738d1b46d7Szhanghch05 inline void userErrorMessageHandler( 2748d1b46d7Szhanghch05 const sd_bus_error* e, const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2758d1b46d7Szhanghch05 const std::string& newUser, const std::string& username) 27666b5ca76Sjayaprakash Mutyala { 27766b5ca76Sjayaprakash Mutyala if (e == nullptr) 27866b5ca76Sjayaprakash Mutyala { 27966b5ca76Sjayaprakash Mutyala messages::internalError(asyncResp->res); 28066b5ca76Sjayaprakash Mutyala return; 28166b5ca76Sjayaprakash Mutyala } 28266b5ca76Sjayaprakash Mutyala 283055806b3SManojkiran Eda const char* errorMessage = e->name; 28466b5ca76Sjayaprakash Mutyala if (strcmp(errorMessage, 28566b5ca76Sjayaprakash Mutyala "xyz.openbmc_project.User.Common.Error.UserNameExists") == 0) 28666b5ca76Sjayaprakash Mutyala { 287d8a5d5d8SJiaqing Zhao messages::resourceAlreadyExists(asyncResp->res, "ManagerAccount", 28866b5ca76Sjayaprakash Mutyala "UserName", newUser); 28966b5ca76Sjayaprakash Mutyala } 29066b5ca76Sjayaprakash Mutyala else if (strcmp(errorMessage, "xyz.openbmc_project.User.Common.Error." 29166b5ca76Sjayaprakash Mutyala "UserNameDoesNotExist") == 0) 29266b5ca76Sjayaprakash Mutyala { 293d8a5d5d8SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "ManagerAccount", username); 29466b5ca76Sjayaprakash Mutyala } 295d4d25793SEd Tanous else if ((strcmp(errorMessage, 296d4d25793SEd Tanous "xyz.openbmc_project.Common.Error.InvalidArgument") == 297d4d25793SEd Tanous 0) || 2980fda0f12SGeorge Liu (strcmp( 2990fda0f12SGeorge Liu errorMessage, 3000fda0f12SGeorge Liu "xyz.openbmc_project.User.Common.Error.UserNameGroupFail") == 3010fda0f12SGeorge Liu 0)) 30266b5ca76Sjayaprakash Mutyala { 30366b5ca76Sjayaprakash Mutyala messages::propertyValueFormatError(asyncResp->res, newUser, "UserName"); 30466b5ca76Sjayaprakash Mutyala } 30566b5ca76Sjayaprakash Mutyala else if (strcmp(errorMessage, 30666b5ca76Sjayaprakash Mutyala "xyz.openbmc_project.User.Common.Error.NoResource") == 0) 30766b5ca76Sjayaprakash Mutyala { 30866b5ca76Sjayaprakash Mutyala messages::createLimitReachedForResource(asyncResp->res); 30966b5ca76Sjayaprakash Mutyala } 31066b5ca76Sjayaprakash Mutyala else 31166b5ca76Sjayaprakash Mutyala { 312b8ad583fSGunnar Mills BMCWEB_LOG_ERROR("DBUS response error {}", errorMessage); 31366b5ca76Sjayaprakash Mutyala messages::internalError(asyncResp->res); 31466b5ca76Sjayaprakash Mutyala } 31566b5ca76Sjayaprakash Mutyala } 31666b5ca76Sjayaprakash Mutyala 31781ce609eSEd Tanous inline void parseLDAPConfigData(nlohmann::json& jsonResponse, 318ab828d7cSRatan Gupta const LDAPConfigData& confData, 319ab828d7cSRatan Gupta const std::string& ldapType) 3206973a582SRatan Gupta { 32149cc263fSEd Tanous nlohmann::json::object_t ldap; 3221476687dSEd Tanous ldap["ServiceEnabled"] = confData.serviceEnabled; 32349cc263fSEd Tanous nlohmann::json::array_t serviceAddresses; 32449cc263fSEd Tanous serviceAddresses.emplace_back(confData.uri); 32549cc263fSEd Tanous ldap["ServiceAddresses"] = std::move(serviceAddresses); 32649cc263fSEd Tanous 32749cc263fSEd Tanous nlohmann::json::object_t authentication; 32849cc263fSEd Tanous authentication["AuthenticationType"] = 3290ec8b83dSEd Tanous account_service::AuthenticationTypes::UsernameAndPassword; 33049cc263fSEd Tanous authentication["Username"] = confData.bindDN; 33149cc263fSEd Tanous authentication["Password"] = nullptr; 33249cc263fSEd Tanous ldap["Authentication"] = std::move(authentication); 3331476687dSEd Tanous 33449cc263fSEd Tanous nlohmann::json::object_t ldapService; 33549cc263fSEd Tanous nlohmann::json::object_t searchSettings; 33649cc263fSEd Tanous nlohmann::json::array_t baseDistinguishedNames; 33749cc263fSEd Tanous baseDistinguishedNames.emplace_back(confData.baseDN); 3381476687dSEd Tanous 33949cc263fSEd Tanous searchSettings["BaseDistinguishedNames"] = 34049cc263fSEd Tanous std::move(baseDistinguishedNames); 34149cc263fSEd Tanous searchSettings["UsernameAttribute"] = confData.userNameAttribute; 34249cc263fSEd Tanous searchSettings["GroupsAttribute"] = confData.groupAttribute; 34349cc263fSEd Tanous ldapService["SearchSettings"] = std::move(searchSettings); 34449cc263fSEd Tanous ldap["LDAPService"] = std::move(ldapService); 34549cc263fSEd Tanous 34649cc263fSEd Tanous nlohmann::json::array_t roleMapArray; 3479eb808c1SEd Tanous for (const auto& obj : confData.groupRoleList) 34854fc587aSNagaraju Goruganti { 34962598e31SEd Tanous BMCWEB_LOG_DEBUG("Pushing the data groupName={}", obj.second.groupName); 350613dabeaSEd Tanous 351613dabeaSEd Tanous nlohmann::json::object_t remoteGroup; 352613dabeaSEd Tanous remoteGroup["RemoteGroup"] = obj.second.groupName; 353329f0348SJorge Cisneros remoteGroup["LocalRole"] = getRoleIdFromPrivilege(obj.second.privilege); 354329f0348SJorge Cisneros roleMapArray.emplace_back(std::move(remoteGroup)); 35554fc587aSNagaraju Goruganti } 35649cc263fSEd Tanous 35749cc263fSEd Tanous ldap["RemoteRoleMapping"] = std::move(roleMapArray); 35849cc263fSEd Tanous 35949cc263fSEd Tanous jsonResponse[ldapType].update(ldap); 3606973a582SRatan Gupta } 3616973a582SRatan Gupta 3626973a582SRatan Gupta /** 36306785244SRatan Gupta * @brief validates given JSON input and then calls appropriate method to 36406785244SRatan Gupta * create, to delete or to set Rolemapping object based on the given input. 36506785244SRatan Gupta * 36606785244SRatan Gupta */ 36723a21a1cSEd Tanous inline void handleRoleMapPatch( 3688d1b46d7Szhanghch05 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 36906785244SRatan Gupta const std::vector<std::pair<std::string, LDAPRoleMapData>>& roleMapObjData, 370c1019828SEd Tanous const std::string& serverType, 371c1019828SEd Tanous std::vector<std::variant<nlohmann::json::object_t, std::nullptr_t>>& input) 37206785244SRatan Gupta { 37306785244SRatan Gupta for (size_t index = 0; index < input.size(); index++) 37406785244SRatan Gupta { 375c1019828SEd Tanous std::variant<nlohmann::json::object_t, std::nullptr_t>& thisJson = 376c1019828SEd Tanous input[index]; 377c1019828SEd Tanous nlohmann::json::object_t* obj = 378c1019828SEd Tanous std::get_if<nlohmann::json::object_t>(&thisJson); 379c1019828SEd Tanous if (obj == nullptr) 38006785244SRatan Gupta { 38106785244SRatan Gupta // delete the existing object 38206785244SRatan Gupta if (index < roleMapObjData.size()) 38306785244SRatan Gupta { 38406785244SRatan Gupta crow::connections::systemBus->async_method_call( 38506785244SRatan Gupta [asyncResp, roleMapObjData, serverType, 3865e7e2dc5SEd Tanous index](const boost::system::error_code& ec) { 38706785244SRatan Gupta if (ec) 38806785244SRatan Gupta { 38962598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error: {}", ec); 39006785244SRatan Gupta messages::internalError(asyncResp->res); 39106785244SRatan Gupta return; 39206785244SRatan Gupta } 393bd79bce8SPatrick Williams asyncResp->res 394bd79bce8SPatrick Williams .jsonValue[serverType]["RemoteRoleMapping"][index] = 395bd79bce8SPatrick Williams nullptr; 39606785244SRatan Gupta }, 39706785244SRatan Gupta ldapDbusService, roleMapObjData[index].first, 39806785244SRatan Gupta "xyz.openbmc_project.Object.Delete", "Delete"); 39906785244SRatan Gupta } 40006785244SRatan Gupta else 40106785244SRatan Gupta { 40262598e31SEd Tanous BMCWEB_LOG_ERROR("Can't delete the object"); 403bd79bce8SPatrick Williams messages::propertyValueTypeError( 404bd79bce8SPatrick Williams asyncResp->res, "null", 405bd79bce8SPatrick Williams "RemoteRoleMapping/" + std::to_string(index)); 40606785244SRatan Gupta return; 40706785244SRatan Gupta } 40806785244SRatan Gupta } 409c1019828SEd Tanous else if (obj->empty()) 41006785244SRatan Gupta { 41106785244SRatan Gupta // Don't do anything for the empty objects,parse next json 41206785244SRatan Gupta // eg {"RemoteRoleMapping",[{}]} 41306785244SRatan Gupta } 41406785244SRatan Gupta else 41506785244SRatan Gupta { 41606785244SRatan Gupta // update/create the object 41706785244SRatan Gupta std::optional<std::string> remoteGroup; 41806785244SRatan Gupta std::optional<std::string> localRole; 41906785244SRatan Gupta 420afc474aeSMyung Bae if (!json_util::readJsonObject( // 421afc474aeSMyung Bae *obj, asyncResp->res, // 422afc474aeSMyung Bae "LocalRole", localRole, // 423afc474aeSMyung Bae "RemoteGroup", remoteGroup // 424afc474aeSMyung Bae )) 42506785244SRatan Gupta { 42606785244SRatan Gupta continue; 42706785244SRatan Gupta } 42806785244SRatan Gupta 42906785244SRatan Gupta // Update existing RoleMapping Object 43006785244SRatan Gupta if (index < roleMapObjData.size()) 43106785244SRatan Gupta { 43262598e31SEd Tanous BMCWEB_LOG_DEBUG("Update Role Map Object"); 43306785244SRatan Gupta // If "RemoteGroup" info is provided 43406785244SRatan Gupta if (remoteGroup) 43506785244SRatan Gupta { 436d02aad39SEd Tanous setDbusProperty( 437e93abac6SGinu George asyncResp, 438d02aad39SEd Tanous std::format("RemoteRoleMapping/{}/RemoteGroup", index), 439e93abac6SGinu George ldapDbusService, roleMapObjData[index].first, 440e93abac6SGinu George "xyz.openbmc_project.User.PrivilegeMapperEntry", 441e93abac6SGinu George "GroupName", *remoteGroup); 44206785244SRatan Gupta } 44306785244SRatan Gupta 44406785244SRatan Gupta // If "LocalRole" info is provided 44506785244SRatan Gupta if (localRole) 44606785244SRatan Gupta { 4476d0b80beSRavi Teja std::string priv = getPrivilegeFromRoleId(*localRole); 4486d0b80beSRavi Teja if (priv.empty()) 4496d0b80beSRavi Teja { 4506d0b80beSRavi Teja messages::propertyValueNotInList( 4516d0b80beSRavi Teja asyncResp->res, *localRole, 4526d0b80beSRavi Teja std::format("RemoteRoleMapping/{}/LocalRole", 4536d0b80beSRavi Teja index)); 4546d0b80beSRavi Teja return; 4556d0b80beSRavi Teja } 456d02aad39SEd Tanous setDbusProperty( 457e93abac6SGinu George asyncResp, 458d02aad39SEd Tanous std::format("RemoteRoleMapping/{}/LocalRole", index), 459e93abac6SGinu George ldapDbusService, roleMapObjData[index].first, 460e93abac6SGinu George "xyz.openbmc_project.User.PrivilegeMapperEntry", 4616d0b80beSRavi Teja "Privilege", priv); 46206785244SRatan Gupta } 46306785244SRatan Gupta } 46406785244SRatan Gupta // Create a new RoleMapping Object. 46506785244SRatan Gupta else 46606785244SRatan Gupta { 46762598e31SEd Tanous BMCWEB_LOG_DEBUG( 46862598e31SEd Tanous "setRoleMappingProperties: Creating new Object"); 469bd79bce8SPatrick Williams std::string pathString = 470bd79bce8SPatrick Williams "RemoteRoleMapping/" + std::to_string(index); 47106785244SRatan Gupta 47206785244SRatan Gupta if (!localRole) 47306785244SRatan Gupta { 47406785244SRatan Gupta messages::propertyMissing(asyncResp->res, 47506785244SRatan Gupta pathString + "/LocalRole"); 47606785244SRatan Gupta continue; 47706785244SRatan Gupta } 47806785244SRatan Gupta if (!remoteGroup) 47906785244SRatan Gupta { 48006785244SRatan Gupta messages::propertyMissing(asyncResp->res, 48106785244SRatan Gupta pathString + "/RemoteGroup"); 48206785244SRatan Gupta continue; 48306785244SRatan Gupta } 48406785244SRatan Gupta 48506785244SRatan Gupta std::string dbusObjectPath; 48606785244SRatan Gupta if (serverType == "ActiveDirectory") 48706785244SRatan Gupta { 4882c70f800SEd Tanous dbusObjectPath = adConfigObject; 48906785244SRatan Gupta } 49006785244SRatan Gupta else if (serverType == "LDAP") 49106785244SRatan Gupta { 49223a21a1cSEd Tanous dbusObjectPath = ldapConfigObjectName; 49306785244SRatan Gupta } 49406785244SRatan Gupta 49562598e31SEd Tanous BMCWEB_LOG_DEBUG("Remote Group={},LocalRole={}", *remoteGroup, 49662598e31SEd Tanous *localRole); 49706785244SRatan Gupta 49806785244SRatan Gupta crow::connections::systemBus->async_method_call( 499271584abSEd Tanous [asyncResp, serverType, localRole, 5005e7e2dc5SEd Tanous remoteGroup](const boost::system::error_code& ec) { 50106785244SRatan Gupta if (ec) 50206785244SRatan Gupta { 50362598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error: {}", ec); 50406785244SRatan Gupta messages::internalError(asyncResp->res); 50506785244SRatan Gupta return; 50606785244SRatan Gupta } 50706785244SRatan Gupta nlohmann::json& remoteRoleJson = 50806785244SRatan Gupta asyncResp->res 50906785244SRatan Gupta .jsonValue[serverType]["RemoteRoleMapping"]; 5101476687dSEd Tanous nlohmann::json::object_t roleMapEntry; 5111476687dSEd Tanous roleMapEntry["LocalRole"] = *localRole; 5121476687dSEd Tanous roleMapEntry["RemoteGroup"] = *remoteGroup; 513b2ba3072SPatrick Williams remoteRoleJson.emplace_back(std::move(roleMapEntry)); 51406785244SRatan Gupta }, 51506785244SRatan Gupta ldapDbusService, dbusObjectPath, ldapPrivMapperInterface, 5163174e4dfSEd Tanous "Create", *remoteGroup, 51706785244SRatan Gupta getPrivilegeFromRoleId(std::move(*localRole))); 51806785244SRatan Gupta } 51906785244SRatan Gupta } 52006785244SRatan Gupta } 52106785244SRatan Gupta } 52206785244SRatan Gupta 52306785244SRatan Gupta /** 5246973a582SRatan Gupta * Function that retrieves all properties for LDAP config object 5256973a582SRatan Gupta * into JSON 5266973a582SRatan Gupta */ 5276973a582SRatan Gupta template <typename CallbackFunc> 528bd79bce8SPatrick Williams inline void 529bd79bce8SPatrick Williams getLDAPConfigData(const std::string& ldapType, CallbackFunc&& callback) 5306973a582SRatan Gupta { 5312b73119cSGeorge Liu constexpr std::array<std::string_view, 2> interfaces = { 5322b73119cSGeorge Liu ldapEnableInterface, ldapConfigInterface}; 53354fc587aSNagaraju Goruganti 5342b73119cSGeorge Liu dbus::utility::getDbusObject( 5352b73119cSGeorge Liu ldapConfigObjectName, interfaces, 5368cb2c024SEd Tanous [callback = std::forward<CallbackFunc>(callback), 537c1019828SEd Tanous ldapType](const boost::system::error_code& ec, 538c1019828SEd Tanous const dbus::utility::MapperGetObject& resp) mutable { 53954fc587aSNagaraju Goruganti if (ec || resp.empty()) 54054fc587aSNagaraju Goruganti { 541bf2ddedeSCarson Labrado BMCWEB_LOG_WARNING( 542bd79bce8SPatrick Williams "DBUS response error during getting of service name: {}", 543bd79bce8SPatrick Williams ec); 54423a21a1cSEd Tanous LDAPConfigData empty{}; 54523a21a1cSEd Tanous callback(false, empty, ldapType); 54654fc587aSNagaraju Goruganti return; 54754fc587aSNagaraju Goruganti } 54854fc587aSNagaraju Goruganti std::string service = resp.begin()->first; 5495eb468daSGeorge Liu sdbusplus::message::object_path path(ldapRootObject); 5505eb468daSGeorge Liu dbus::utility::getManagedObjects( 5515eb468daSGeorge Liu service, path, 552bd79bce8SPatrick Williams [callback, ldapType](const boost::system::error_code& ec2, 553bd79bce8SPatrick Williams const dbus::utility::ManagedObjectType& 554bd79bce8SPatrick Williams ldapObjects) mutable { 5556973a582SRatan Gupta LDAPConfigData confData{}; 5568b24275dSEd Tanous if (ec2) 5576973a582SRatan Gupta { 558ab828d7cSRatan Gupta callback(false, confData, ldapType); 559bf2ddedeSCarson Labrado BMCWEB_LOG_WARNING("D-Bus responses error: {}", ec2); 5606973a582SRatan Gupta return; 5616973a582SRatan Gupta } 562ab828d7cSRatan Gupta 563ab828d7cSRatan Gupta std::string ldapDbusType; 56454fc587aSNagaraju Goruganti std::string searchString; 56554fc587aSNagaraju Goruganti 566ab828d7cSRatan Gupta if (ldapType == "LDAP") 567ab828d7cSRatan Gupta { 5680fda0f12SGeorge Liu ldapDbusType = 5690fda0f12SGeorge Liu "xyz.openbmc_project.User.Ldap.Config.Type.OpenLdap"; 57054fc587aSNagaraju Goruganti searchString = "openldap"; 571ab828d7cSRatan Gupta } 572ab828d7cSRatan Gupta else if (ldapType == "ActiveDirectory") 573ab828d7cSRatan Gupta { 57454fc587aSNagaraju Goruganti ldapDbusType = 5750fda0f12SGeorge Liu "xyz.openbmc_project.User.Ldap.Config.Type.ActiveDirectory"; 57654fc587aSNagaraju Goruganti searchString = "active_directory"; 577ab828d7cSRatan Gupta } 578ab828d7cSRatan Gupta else 579ab828d7cSRatan Gupta { 580bd79bce8SPatrick Williams BMCWEB_LOG_ERROR( 581bd79bce8SPatrick Williams "Can't get the DbusType for the given type={}", 58262598e31SEd Tanous ldapType); 583ab828d7cSRatan Gupta callback(false, confData, ldapType); 584ab828d7cSRatan Gupta return; 585ab828d7cSRatan Gupta } 586ab828d7cSRatan Gupta 587ab828d7cSRatan Gupta std::string ldapEnableInterfaceStr = ldapEnableInterface; 588ab828d7cSRatan Gupta std::string ldapConfigInterfaceStr = ldapConfigInterface; 589ab828d7cSRatan Gupta 5906973a582SRatan Gupta for (const auto& object : ldapObjects) 5916973a582SRatan Gupta { 59254fc587aSNagaraju Goruganti // let's find the object whose ldap type is equal to the 59354fc587aSNagaraju Goruganti // given type 594bd79bce8SPatrick Williams if (object.first.str.find(searchString) == 595bd79bce8SPatrick Williams std::string::npos) 5966973a582SRatan Gupta { 597ab828d7cSRatan Gupta continue; 598ab828d7cSRatan Gupta } 599ab828d7cSRatan Gupta 6006973a582SRatan Gupta for (const auto& interface : object.second) 6016973a582SRatan Gupta { 6026973a582SRatan Gupta if (interface.first == ldapEnableInterfaceStr) 6036973a582SRatan Gupta { 6046973a582SRatan Gupta // rest of the properties are string. 6056973a582SRatan Gupta for (const auto& property : interface.second) 6066973a582SRatan Gupta { 6076973a582SRatan Gupta if (property.first == "Enabled") 6086973a582SRatan Gupta { 6096973a582SRatan Gupta const bool* value = 6106973a582SRatan Gupta std::get_if<bool>(&property.second); 6116973a582SRatan Gupta if (value == nullptr) 6126973a582SRatan Gupta { 6136973a582SRatan Gupta continue; 6146973a582SRatan Gupta } 6156973a582SRatan Gupta confData.serviceEnabled = *value; 6166973a582SRatan Gupta break; 6176973a582SRatan Gupta } 6186973a582SRatan Gupta } 6196973a582SRatan Gupta } 6206973a582SRatan Gupta else if (interface.first == ldapConfigInterfaceStr) 6216973a582SRatan Gupta { 6226973a582SRatan Gupta for (const auto& property : interface.second) 6236973a582SRatan Gupta { 624271584abSEd Tanous const std::string* strValue = 625bd79bce8SPatrick Williams std::get_if<std::string>( 626bd79bce8SPatrick Williams &property.second); 627271584abSEd Tanous if (strValue == nullptr) 6286973a582SRatan Gupta { 6296973a582SRatan Gupta continue; 6306973a582SRatan Gupta } 6316973a582SRatan Gupta if (property.first == "LDAPServerURI") 6326973a582SRatan Gupta { 633271584abSEd Tanous confData.uri = *strValue; 6346973a582SRatan Gupta } 6356973a582SRatan Gupta else if (property.first == "LDAPBindDN") 6366973a582SRatan Gupta { 637271584abSEd Tanous confData.bindDN = *strValue; 6386973a582SRatan Gupta } 6396973a582SRatan Gupta else if (property.first == "LDAPBaseDN") 6406973a582SRatan Gupta { 641271584abSEd Tanous confData.baseDN = *strValue; 6426973a582SRatan Gupta } 643bd79bce8SPatrick Williams else if (property.first == 644bd79bce8SPatrick Williams "LDAPSearchScope") 6456973a582SRatan Gupta { 646271584abSEd Tanous confData.searchScope = *strValue; 6476973a582SRatan Gupta } 648bd79bce8SPatrick Williams else if (property.first == 649bd79bce8SPatrick Williams "GroupNameAttribute") 6506973a582SRatan Gupta { 651271584abSEd Tanous confData.groupAttribute = *strValue; 6526973a582SRatan Gupta } 653bd79bce8SPatrick Williams else if (property.first == 654bd79bce8SPatrick Williams "UserNameAttribute") 6556973a582SRatan Gupta { 656271584abSEd Tanous confData.userNameAttribute = *strValue; 6576973a582SRatan Gupta } 65854fc587aSNagaraju Goruganti else if (property.first == "LDAPType") 659ab828d7cSRatan Gupta { 660271584abSEd Tanous confData.serverType = *strValue; 66154fc587aSNagaraju Goruganti } 66254fc587aSNagaraju Goruganti } 66354fc587aSNagaraju Goruganti } 664bd79bce8SPatrick Williams else if ( 665bd79bce8SPatrick Williams interface.first == 6660fda0f12SGeorge Liu "xyz.openbmc_project.User.PrivilegeMapperEntry") 66754fc587aSNagaraju Goruganti { 66854fc587aSNagaraju Goruganti LDAPRoleMapData roleMapData{}; 66954fc587aSNagaraju Goruganti for (const auto& property : interface.second) 67054fc587aSNagaraju Goruganti { 671271584abSEd Tanous const std::string* strValue = 672bd79bce8SPatrick Williams std::get_if<std::string>( 673bd79bce8SPatrick Williams &property.second); 67454fc587aSNagaraju Goruganti 675271584abSEd Tanous if (strValue == nullptr) 67654fc587aSNagaraju Goruganti { 67754fc587aSNagaraju Goruganti continue; 67854fc587aSNagaraju Goruganti } 67954fc587aSNagaraju Goruganti 68054fc587aSNagaraju Goruganti if (property.first == "GroupName") 68154fc587aSNagaraju Goruganti { 682271584abSEd Tanous roleMapData.groupName = *strValue; 68354fc587aSNagaraju Goruganti } 68454fc587aSNagaraju Goruganti else if (property.first == "Privilege") 68554fc587aSNagaraju Goruganti { 686271584abSEd Tanous roleMapData.privilege = *strValue; 68754fc587aSNagaraju Goruganti } 68854fc587aSNagaraju Goruganti } 68954fc587aSNagaraju Goruganti 690bd79bce8SPatrick Williams confData.groupRoleList.emplace_back( 691bd79bce8SPatrick Williams object.first.str, roleMapData); 69254fc587aSNagaraju Goruganti } 69354fc587aSNagaraju Goruganti } 69454fc587aSNagaraju Goruganti } 695ab828d7cSRatan Gupta callback(true, confData, ldapType); 6965eb468daSGeorge Liu }); 6972b73119cSGeorge Liu }); 6986973a582SRatan Gupta } 6996973a582SRatan Gupta 7008a07d286SRatan Gupta /** 7018a07d286SRatan Gupta * @brief updates the LDAP server address and updates the 7028a07d286SRatan Gupta json response with the new value. 7038a07d286SRatan Gupta * @param serviceAddressList address to be updated. 7048a07d286SRatan Gupta * @param asyncResp pointer to the JSON response 7058a07d286SRatan Gupta * @param ldapServerElementName Type of LDAP 7068a07d286SRatan Gupta server(openLDAP/ActiveDirectory) 7078a07d286SRatan Gupta */ 7088a07d286SRatan Gupta 7094f48d5f6SEd Tanous inline void handleServiceAddressPatch( 7108a07d286SRatan Gupta const std::vector<std::string>& serviceAddressList, 7118d1b46d7Szhanghch05 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 7128a07d286SRatan Gupta const std::string& ldapServerElementName, 7138a07d286SRatan Gupta const std::string& ldapConfigObject) 7148a07d286SRatan Gupta { 715e93abac6SGinu George setDbusProperty(asyncResp, ldapServerElementName + "/ServiceAddress", 716e93abac6SGinu George ldapDbusService, ldapConfigObject, ldapConfigInterface, 717e93abac6SGinu George "LDAPServerURI", serviceAddressList.front()); 7188a07d286SRatan Gupta } 7198a07d286SRatan Gupta /** 7208a07d286SRatan Gupta * @brief updates the LDAP Bind DN and updates the 7218a07d286SRatan Gupta json response with the new value. 7228a07d286SRatan Gupta * @param username name of the user which needs to be updated. 7238a07d286SRatan Gupta * @param asyncResp pointer to the JSON response 7248a07d286SRatan Gupta * @param ldapServerElementName Type of LDAP 7258a07d286SRatan Gupta server(openLDAP/ActiveDirectory) 7268a07d286SRatan Gupta */ 7278a07d286SRatan Gupta 7284f48d5f6SEd Tanous inline void 7294f48d5f6SEd Tanous handleUserNamePatch(const std::string& username, 7308d1b46d7Szhanghch05 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 7318a07d286SRatan Gupta const std::string& ldapServerElementName, 7328a07d286SRatan Gupta const std::string& ldapConfigObject) 7338a07d286SRatan Gupta { 734e93abac6SGinu George setDbusProperty(asyncResp, 735d02aad39SEd Tanous ldapServerElementName + "/Authentication/Username", 736e93abac6SGinu George ldapDbusService, ldapConfigObject, ldapConfigInterface, 737e93abac6SGinu George "LDAPBindDN", username); 7388a07d286SRatan Gupta } 7398a07d286SRatan Gupta 7408a07d286SRatan Gupta /** 7418a07d286SRatan Gupta * @brief updates the LDAP password 7428a07d286SRatan Gupta * @param password : ldap password which needs to be updated. 7438a07d286SRatan Gupta * @param asyncResp pointer to the JSON response 7448a07d286SRatan Gupta * @param ldapServerElementName Type of LDAP 7458a07d286SRatan Gupta * server(openLDAP/ActiveDirectory) 7468a07d286SRatan Gupta */ 7478a07d286SRatan Gupta 7484f48d5f6SEd Tanous inline void 7494f48d5f6SEd Tanous handlePasswordPatch(const std::string& password, 7508d1b46d7Szhanghch05 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 7518a07d286SRatan Gupta const std::string& ldapServerElementName, 7528a07d286SRatan Gupta const std::string& ldapConfigObject) 7538a07d286SRatan Gupta { 754e93abac6SGinu George setDbusProperty(asyncResp, 755d02aad39SEd Tanous ldapServerElementName + "/Authentication/Password", 756e93abac6SGinu George ldapDbusService, ldapConfigObject, ldapConfigInterface, 757e93abac6SGinu George "LDAPBindDNPassword", password); 7588a07d286SRatan Gupta } 7598a07d286SRatan Gupta 7608a07d286SRatan Gupta /** 7618a07d286SRatan Gupta * @brief updates the LDAP BaseDN and updates the 7628a07d286SRatan Gupta json response with the new value. 7638a07d286SRatan Gupta * @param baseDNList baseDN list which needs to be updated. 7648a07d286SRatan Gupta * @param asyncResp pointer to the JSON response 7658a07d286SRatan Gupta * @param ldapServerElementName Type of LDAP 7668a07d286SRatan Gupta server(openLDAP/ActiveDirectory) 7678a07d286SRatan Gupta */ 7688a07d286SRatan Gupta 7694f48d5f6SEd Tanous inline void 7704f48d5f6SEd Tanous handleBaseDNPatch(const std::vector<std::string>& baseDNList, 7718d1b46d7Szhanghch05 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 7728a07d286SRatan Gupta const std::string& ldapServerElementName, 7738a07d286SRatan Gupta const std::string& ldapConfigObject) 7748a07d286SRatan Gupta { 775e93abac6SGinu George setDbusProperty(asyncResp, 776d02aad39SEd Tanous ldapServerElementName + 777d02aad39SEd Tanous "/LDAPService/SearchSettings/BaseDistinguishedNames", 778e93abac6SGinu George ldapDbusService, ldapConfigObject, ldapConfigInterface, 779e93abac6SGinu George "LDAPBaseDN", baseDNList.front()); 7808a07d286SRatan Gupta } 7818a07d286SRatan Gupta /** 7828a07d286SRatan Gupta * @brief updates the LDAP user name attribute and updates the 7838a07d286SRatan Gupta json response with the new value. 7848a07d286SRatan Gupta * @param userNameAttribute attribute to be updated. 7858a07d286SRatan Gupta * @param asyncResp pointer to the JSON response 7868a07d286SRatan Gupta * @param ldapServerElementName Type of LDAP 7878a07d286SRatan Gupta server(openLDAP/ActiveDirectory) 7888a07d286SRatan Gupta */ 7898a07d286SRatan Gupta 790bd79bce8SPatrick Williams inline void handleUserNameAttrPatch( 791bd79bce8SPatrick Williams const std::string& userNameAttribute, 7928d1b46d7Szhanghch05 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 7938a07d286SRatan Gupta const std::string& ldapServerElementName, 7948a07d286SRatan Gupta const std::string& ldapConfigObject) 7958a07d286SRatan Gupta { 796bd79bce8SPatrick Williams setDbusProperty( 797bd79bce8SPatrick Williams asyncResp, 798bd79bce8SPatrick Williams ldapServerElementName + "LDAPService/SearchSettings/UsernameAttribute", 799e93abac6SGinu George ldapDbusService, ldapConfigObject, ldapConfigInterface, 800e93abac6SGinu George "UserNameAttribute", userNameAttribute); 8018a07d286SRatan Gupta } 8028a07d286SRatan Gupta /** 8038a07d286SRatan Gupta * @brief updates the LDAP group attribute and updates the 8048a07d286SRatan Gupta json response with the new value. 8058a07d286SRatan Gupta * @param groupsAttribute attribute to be updated. 8068a07d286SRatan Gupta * @param asyncResp pointer to the JSON response 8078a07d286SRatan Gupta * @param ldapServerElementName Type of LDAP 8088a07d286SRatan Gupta server(openLDAP/ActiveDirectory) 8098a07d286SRatan Gupta */ 8108a07d286SRatan Gupta 8114f48d5f6SEd Tanous inline void handleGroupNameAttrPatch( 8128d1b46d7Szhanghch05 const std::string& groupsAttribute, 8138d1b46d7Szhanghch05 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 8148a07d286SRatan Gupta const std::string& ldapServerElementName, 8158a07d286SRatan Gupta const std::string& ldapConfigObject) 8168a07d286SRatan Gupta { 817bd79bce8SPatrick Williams setDbusProperty( 818bd79bce8SPatrick Williams asyncResp, 819bd79bce8SPatrick Williams ldapServerElementName + "/LDAPService/SearchSettings/GroupsAttribute", 820e93abac6SGinu George ldapDbusService, ldapConfigObject, ldapConfigInterface, 821e93abac6SGinu George "GroupNameAttribute", groupsAttribute); 8228a07d286SRatan Gupta } 8238a07d286SRatan Gupta /** 8248a07d286SRatan Gupta * @brief updates the LDAP service enable and updates the 8258a07d286SRatan Gupta json response with the new value. 8268a07d286SRatan Gupta * @param input JSON data. 8278a07d286SRatan Gupta * @param asyncResp pointer to the JSON response 8288a07d286SRatan Gupta * @param ldapServerElementName Type of LDAP 8298a07d286SRatan Gupta server(openLDAP/ActiveDirectory) 8308a07d286SRatan Gupta */ 8318a07d286SRatan Gupta 8324f48d5f6SEd Tanous inline void handleServiceEnablePatch( 8336c51eab1SEd Tanous bool serviceEnabled, const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 8348a07d286SRatan Gupta const std::string& ldapServerElementName, 8358a07d286SRatan Gupta const std::string& ldapConfigObject) 8368a07d286SRatan Gupta { 837e93abac6SGinu George setDbusProperty(asyncResp, ldapServerElementName + "/ServiceEnabled", 838e93abac6SGinu George ldapDbusService, ldapConfigObject, ldapEnableInterface, 839e93abac6SGinu George "Enabled", serviceEnabled); 8408a07d286SRatan Gupta } 8418a07d286SRatan Gupta 842c1019828SEd Tanous struct AuthMethods 84378158631SZbigniew Kurzynski { 84478158631SZbigniew Kurzynski std::optional<bool> basicAuth; 84578158631SZbigniew Kurzynski std::optional<bool> cookie; 84678158631SZbigniew Kurzynski std::optional<bool> sessionToken; 84778158631SZbigniew Kurzynski std::optional<bool> xToken; 848501f1e58SZbigniew Kurzynski std::optional<bool> tls; 849c1019828SEd Tanous }; 85078158631SZbigniew Kurzynski 851c1019828SEd Tanous inline void 852c1019828SEd Tanous handleAuthMethodsPatch(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 853c1019828SEd Tanous const AuthMethods& auth) 85478158631SZbigniew Kurzynski { 855c1019828SEd Tanous persistent_data::AuthConfigMethods& authMethodsConfig = 85652cc112dSEd Tanous persistent_data::SessionStore::getInstance().getAuthMethodsConfig(); 85778158631SZbigniew Kurzynski 858c1019828SEd Tanous if (auth.basicAuth) 85978158631SZbigniew Kurzynski { 86025b54dbaSEd Tanous if constexpr (!BMCWEB_BASIC_AUTH) 86125b54dbaSEd Tanous { 862f16f6263SAlan Kuo messages::actionNotSupported( 8630fda0f12SGeorge Liu asyncResp->res, 8640fda0f12SGeorge Liu "Setting BasicAuth when basic-auth feature is disabled"); 865f16f6263SAlan Kuo return; 86625b54dbaSEd Tanous } 86725b54dbaSEd Tanous 868c1019828SEd Tanous authMethodsConfig.basic = *auth.basicAuth; 86978158631SZbigniew Kurzynski } 87078158631SZbigniew Kurzynski 871c1019828SEd Tanous if (auth.cookie) 87278158631SZbigniew Kurzynski { 87325b54dbaSEd Tanous if constexpr (!BMCWEB_COOKIE_AUTH) 87425b54dbaSEd Tanous { 8750fda0f12SGeorge Liu messages::actionNotSupported( 8760fda0f12SGeorge Liu asyncResp->res, 8770fda0f12SGeorge Liu "Setting Cookie when cookie-auth feature is disabled"); 878f16f6263SAlan Kuo return; 87925b54dbaSEd Tanous } 880c1019828SEd Tanous authMethodsConfig.cookie = *auth.cookie; 88178158631SZbigniew Kurzynski } 88278158631SZbigniew Kurzynski 883c1019828SEd Tanous if (auth.sessionToken) 88478158631SZbigniew Kurzynski { 88525b54dbaSEd Tanous if constexpr (!BMCWEB_SESSION_AUTH) 88625b54dbaSEd Tanous { 887f16f6263SAlan Kuo messages::actionNotSupported( 8880fda0f12SGeorge Liu asyncResp->res, 8890fda0f12SGeorge Liu "Setting SessionToken when session-auth feature is disabled"); 890f16f6263SAlan Kuo return; 89125b54dbaSEd Tanous } 892c1019828SEd Tanous authMethodsConfig.sessionToken = *auth.sessionToken; 89378158631SZbigniew Kurzynski } 89478158631SZbigniew Kurzynski 895c1019828SEd Tanous if (auth.xToken) 89678158631SZbigniew Kurzynski { 89725b54dbaSEd Tanous if constexpr (!BMCWEB_XTOKEN_AUTH) 89825b54dbaSEd Tanous { 8990fda0f12SGeorge Liu messages::actionNotSupported( 9000fda0f12SGeorge Liu asyncResp->res, 9010fda0f12SGeorge Liu "Setting XToken when xtoken-auth feature is disabled"); 902f16f6263SAlan Kuo return; 90325b54dbaSEd Tanous } 904c1019828SEd Tanous authMethodsConfig.xtoken = *auth.xToken; 90578158631SZbigniew Kurzynski } 90678158631SZbigniew Kurzynski 907c1019828SEd Tanous if (auth.tls) 908501f1e58SZbigniew Kurzynski { 90925b54dbaSEd Tanous if constexpr (!BMCWEB_MUTUAL_TLS_AUTH) 91025b54dbaSEd Tanous { 9110fda0f12SGeorge Liu messages::actionNotSupported( 9120fda0f12SGeorge Liu asyncResp->res, 9130fda0f12SGeorge Liu "Setting TLS when mutual-tls-auth feature is disabled"); 914f16f6263SAlan Kuo return; 91525b54dbaSEd Tanous } 916c1019828SEd Tanous authMethodsConfig.tls = *auth.tls; 917501f1e58SZbigniew Kurzynski } 918501f1e58SZbigniew Kurzynski 91978158631SZbigniew Kurzynski if (!authMethodsConfig.basic && !authMethodsConfig.cookie && 920501f1e58SZbigniew Kurzynski !authMethodsConfig.sessionToken && !authMethodsConfig.xtoken && 921501f1e58SZbigniew Kurzynski !authMethodsConfig.tls) 92278158631SZbigniew Kurzynski { 92378158631SZbigniew Kurzynski // Do not allow user to disable everything 92478158631SZbigniew Kurzynski messages::actionNotSupported(asyncResp->res, 92578158631SZbigniew Kurzynski "of disabling all available methods"); 92678158631SZbigniew Kurzynski return; 92778158631SZbigniew Kurzynski } 92878158631SZbigniew Kurzynski 92952cc112dSEd Tanous persistent_data::SessionStore::getInstance().updateAuthMethodsConfig( 93052cc112dSEd Tanous authMethodsConfig); 93178158631SZbigniew Kurzynski // Save configuration immediately 93252cc112dSEd Tanous persistent_data::getConfig().writeData(); 93378158631SZbigniew Kurzynski 93478158631SZbigniew Kurzynski messages::success(asyncResp->res); 93578158631SZbigniew Kurzynski } 93678158631SZbigniew Kurzynski 9378a07d286SRatan Gupta /** 9388a07d286SRatan Gupta * @brief Get the required values from the given JSON, validates the 9398a07d286SRatan Gupta * value and create the LDAP config object. 9408a07d286SRatan Gupta * @param input JSON data 9418a07d286SRatan Gupta * @param asyncResp pointer to the JSON response 9428a07d286SRatan Gupta * @param serverType Type of LDAP server(openLDAP/ActiveDirectory) 9438a07d286SRatan Gupta */ 9448a07d286SRatan Gupta 94510cb44f3SEd Tanous struct LdapPatchParams 94610cb44f3SEd Tanous { 94710cb44f3SEd Tanous std::optional<std::string> authType; 94810cb44f3SEd Tanous std::optional<std::vector<std::string>> serviceAddressList; 94910cb44f3SEd Tanous std::optional<bool> serviceEnabled; 95010cb44f3SEd Tanous std::optional<std::vector<std::string>> baseDNList; 95110cb44f3SEd Tanous std::optional<std::string> userNameAttribute; 95210cb44f3SEd Tanous std::optional<std::string> groupsAttribute; 95310cb44f3SEd Tanous std::optional<std::string> userName; 95410cb44f3SEd Tanous std::optional<std::string> password; 95510cb44f3SEd Tanous std::optional< 95610cb44f3SEd Tanous std::vector<std::variant<nlohmann::json::object_t, std::nullptr_t>>> 95710cb44f3SEd Tanous remoteRoleMapData; 95810cb44f3SEd Tanous }; 95910cb44f3SEd Tanous 96010cb44f3SEd Tanous inline void handleLDAPPatch(LdapPatchParams&& input, 9618d1b46d7Szhanghch05 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 9628a07d286SRatan Gupta const std::string& serverType) 9638a07d286SRatan Gupta { 964eb2bbe56SRatan Gupta std::string dbusObjectPath; 965eb2bbe56SRatan Gupta if (serverType == "ActiveDirectory") 966eb2bbe56SRatan Gupta { 9672c70f800SEd Tanous dbusObjectPath = adConfigObject; 968eb2bbe56SRatan Gupta } 969eb2bbe56SRatan Gupta else if (serverType == "LDAP") 970eb2bbe56SRatan Gupta { 97123a21a1cSEd Tanous dbusObjectPath = ldapConfigObjectName; 972eb2bbe56SRatan Gupta } 973cb13a392SEd Tanous else 974cb13a392SEd Tanous { 97510cb44f3SEd Tanous BMCWEB_LOG_ERROR("serverType wasn't AD or LDAP but was {}????", 97610cb44f3SEd Tanous serverType); 977cb13a392SEd Tanous return; 978cb13a392SEd Tanous } 979eb2bbe56SRatan Gupta 98010cb44f3SEd Tanous if (input.authType && *input.authType != "UsernameAndPassword") 9818a07d286SRatan Gupta { 98210cb44f3SEd Tanous messages::propertyValueNotInList(asyncResp->res, *input.authType, 983c1019828SEd Tanous "AuthenticationType"); 984c1019828SEd Tanous return; 9858a07d286SRatan Gupta } 986c1019828SEd Tanous 98710cb44f3SEd Tanous if (input.serviceAddressList) 9888a07d286SRatan Gupta { 98910cb44f3SEd Tanous if (input.serviceAddressList->empty()) 9908a07d286SRatan Gupta { 991e2616cc5SEd Tanous messages::propertyValueNotInList( 99210cb44f3SEd Tanous asyncResp->res, *input.serviceAddressList, "ServiceAddress"); 9938a07d286SRatan Gupta return; 9948a07d286SRatan Gupta } 9958a07d286SRatan Gupta } 99610cb44f3SEd Tanous if (input.baseDNList) 9978a07d286SRatan Gupta { 99810cb44f3SEd Tanous if (input.baseDNList->empty()) 9998a07d286SRatan Gupta { 100010cb44f3SEd Tanous messages::propertyValueNotInList(asyncResp->res, *input.baseDNList, 10018a07d286SRatan Gupta "BaseDistinguishedNames"); 10028a07d286SRatan Gupta return; 10038a07d286SRatan Gupta } 10048a07d286SRatan Gupta } 10058a07d286SRatan Gupta 10068a07d286SRatan Gupta // nothing to update, then return 100710cb44f3SEd Tanous if (!input.userName && !input.password && !input.serviceAddressList && 100810cb44f3SEd Tanous !input.baseDNList && !input.userNameAttribute && 100910cb44f3SEd Tanous !input.groupsAttribute && !input.serviceEnabled && 101010cb44f3SEd Tanous !input.remoteRoleMapData) 10118a07d286SRatan Gupta { 10128a07d286SRatan Gupta return; 10138a07d286SRatan Gupta } 10148a07d286SRatan Gupta 10158a07d286SRatan Gupta // Get the existing resource first then keep modifying 10168a07d286SRatan Gupta // whenever any property gets updated. 1017bd79bce8SPatrick Williams getLDAPConfigData(serverType, [asyncResp, input = std::move(input), 101810cb44f3SEd Tanous dbusObjectPath = std::move(dbusObjectPath)]( 1019bd79bce8SPatrick Williams bool success, 1020bd79bce8SPatrick Williams const LDAPConfigData& confData, 1021c1019828SEd Tanous const std::string& serverT) mutable { 10228a07d286SRatan Gupta if (!success) 10238a07d286SRatan Gupta { 10248a07d286SRatan Gupta messages::internalError(asyncResp->res); 10258a07d286SRatan Gupta return; 10268a07d286SRatan Gupta } 10276c51eab1SEd Tanous parseLDAPConfigData(asyncResp->res.jsonValue, confData, serverT); 10288a07d286SRatan Gupta if (confData.serviceEnabled) 10298a07d286SRatan Gupta { 10308a07d286SRatan Gupta // Disable the service first and update the rest of 10318a07d286SRatan Gupta // the properties. 10326c51eab1SEd Tanous handleServiceEnablePatch(false, asyncResp, serverT, dbusObjectPath); 10338a07d286SRatan Gupta } 10348a07d286SRatan Gupta 103510cb44f3SEd Tanous if (input.serviceAddressList) 10368a07d286SRatan Gupta { 103710cb44f3SEd Tanous handleServiceAddressPatch(*input.serviceAddressList, asyncResp, 103810cb44f3SEd Tanous serverT, dbusObjectPath); 103910cb44f3SEd Tanous } 104010cb44f3SEd Tanous if (input.userName) 104110cb44f3SEd Tanous { 104210cb44f3SEd Tanous handleUserNamePatch(*input.userName, asyncResp, serverT, 10436c51eab1SEd Tanous dbusObjectPath); 10448a07d286SRatan Gupta } 104510cb44f3SEd Tanous if (input.password) 10468a07d286SRatan Gupta { 104710cb44f3SEd Tanous handlePasswordPatch(*input.password, asyncResp, serverT, 104810cb44f3SEd Tanous dbusObjectPath); 10498a07d286SRatan Gupta } 10508a07d286SRatan Gupta 105110cb44f3SEd Tanous if (input.baseDNList) 10528a07d286SRatan Gupta { 105310cb44f3SEd Tanous handleBaseDNPatch(*input.baseDNList, asyncResp, serverT, 10546c51eab1SEd Tanous dbusObjectPath); 10558a07d286SRatan Gupta } 105610cb44f3SEd Tanous if (input.userNameAttribute) 10578a07d286SRatan Gupta { 105810cb44f3SEd Tanous handleUserNameAttrPatch(*input.userNameAttribute, asyncResp, 105910cb44f3SEd Tanous serverT, dbusObjectPath); 106010cb44f3SEd Tanous } 106110cb44f3SEd Tanous if (input.groupsAttribute) 106210cb44f3SEd Tanous { 106310cb44f3SEd Tanous handleGroupNameAttrPatch(*input.groupsAttribute, asyncResp, serverT, 10646c51eab1SEd Tanous dbusObjectPath); 10658a07d286SRatan Gupta } 106610cb44f3SEd Tanous if (input.serviceEnabled) 10678a07d286SRatan Gupta { 10688a07d286SRatan Gupta // if user has given the value as true then enable 10698a07d286SRatan Gupta // the service. if user has given false then no-op 10708a07d286SRatan Gupta // as service is already stopped. 107110cb44f3SEd Tanous if (*input.serviceEnabled) 10728a07d286SRatan Gupta { 107310cb44f3SEd Tanous handleServiceEnablePatch(*input.serviceEnabled, asyncResp, 107410cb44f3SEd Tanous serverT, dbusObjectPath); 10758a07d286SRatan Gupta } 10768a07d286SRatan Gupta } 10778a07d286SRatan Gupta else 10788a07d286SRatan Gupta { 10798a07d286SRatan Gupta // if user has not given the service enabled value 10808a07d286SRatan Gupta // then revert it to the same state as it was 10818a07d286SRatan Gupta // before. 10828a07d286SRatan Gupta handleServiceEnablePatch(confData.serviceEnabled, asyncResp, 108323a21a1cSEd Tanous serverT, dbusObjectPath); 10848a07d286SRatan Gupta } 108506785244SRatan Gupta 108610cb44f3SEd Tanous if (input.remoteRoleMapData) 108706785244SRatan Gupta { 10886c51eab1SEd Tanous handleRoleMapPatch(asyncResp, confData.groupRoleList, serverT, 108910cb44f3SEd Tanous *input.remoteRoleMapData); 109006785244SRatan Gupta } 10918a07d286SRatan Gupta }); 10928a07d286SRatan Gupta } 1093d4b5443fSEd Tanous 1094*492ec93aSEd Tanous struct UserUpdateParams 10951abe55efSEd Tanous { 1096*492ec93aSEd Tanous std::string username; 1097*492ec93aSEd Tanous std::optional<std::string> password; 1098*492ec93aSEd Tanous std::optional<bool> enabled; 1099*492ec93aSEd Tanous std::optional<std::string> roleId; 1100*492ec93aSEd Tanous std::optional<bool> locked; 1101*492ec93aSEd Tanous std::optional<std::vector<std::string>> accountTypes; 1102*492ec93aSEd Tanous bool userSelf; 1103*492ec93aSEd Tanous std::shared_ptr<persistent_data::UserSession> session; 1104*492ec93aSEd Tanous std::string dbusObjectPath; 1105*492ec93aSEd Tanous }; 11066c51eab1SEd Tanous 1107*492ec93aSEd Tanous inline void 1108*492ec93aSEd Tanous afterVerifyUserExists(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1109*492ec93aSEd Tanous const UserUpdateParams& params, int rc) 1110*492ec93aSEd Tanous { 1111e662eae8SEd Tanous if (rc <= 0) 11126c51eab1SEd Tanous { 1113d8a5d5d8SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "ManagerAccount", 1114*492ec93aSEd Tanous params.username); 11156c51eab1SEd Tanous return; 11166c51eab1SEd Tanous } 11176c51eab1SEd Tanous 1118*492ec93aSEd Tanous if (params.password) 11196c51eab1SEd Tanous { 1120*492ec93aSEd Tanous int retval = pamUpdatePassword(params.username, *params.password); 11216c51eab1SEd Tanous 11226c51eab1SEd Tanous if (retval == PAM_USER_UNKNOWN) 11236c51eab1SEd Tanous { 1124d8a5d5d8SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "ManagerAccount", 1125*492ec93aSEd Tanous params.username); 11266c51eab1SEd Tanous } 11276c51eab1SEd Tanous else if (retval == PAM_AUTHTOK_ERR) 11286c51eab1SEd Tanous { 11296c51eab1SEd Tanous // If password is invalid 11309bd80831SJason M. Bills messages::propertyValueFormatError(asyncResp->res, nullptr, 11319bd80831SJason M. Bills "Password"); 113262598e31SEd Tanous BMCWEB_LOG_ERROR("pamUpdatePassword Failed"); 11336c51eab1SEd Tanous } 11346c51eab1SEd Tanous else if (retval != PAM_SUCCESS) 11356c51eab1SEd Tanous { 11366c51eab1SEd Tanous messages::internalError(asyncResp->res); 11376c51eab1SEd Tanous return; 11386c51eab1SEd Tanous } 1139e7b1b62bSEd Tanous else 1140e7b1b62bSEd Tanous { 1141bd79bce8SPatrick Williams // Remove existing sessions of the user when password 1142bd79bce8SPatrick Williams // changed 1143e518ef32SRavi Teja persistent_data::SessionStore::getInstance() 1144*492ec93aSEd Tanous .removeSessionsByUsernameExceptSession(params.username, 1145*492ec93aSEd Tanous params.session); 1146e7b1b62bSEd Tanous messages::success(asyncResp->res); 1147e7b1b62bSEd Tanous } 11486c51eab1SEd Tanous } 11496c51eab1SEd Tanous 1150*492ec93aSEd Tanous if (params.enabled) 11516c51eab1SEd Tanous { 1152bd79bce8SPatrick Williams setDbusProperty( 1153bd79bce8SPatrick Williams asyncResp, "Enabled", "xyz.openbmc_project.User.Manager", 1154*492ec93aSEd Tanous params.dbusObjectPath, "xyz.openbmc_project.User.Attributes", 1155*492ec93aSEd Tanous "UserEnabled", *params.enabled); 11566c51eab1SEd Tanous } 11576c51eab1SEd Tanous 1158*492ec93aSEd Tanous if (params.roleId) 11596c51eab1SEd Tanous { 1160*492ec93aSEd Tanous std::string priv = getPrivilegeFromRoleId(*params.roleId); 11616c51eab1SEd Tanous if (priv.empty()) 11626c51eab1SEd Tanous { 1163*492ec93aSEd Tanous messages::propertyValueNotInList(asyncResp->res, true, "Locked"); 11646c51eab1SEd Tanous return; 11656c51eab1SEd Tanous } 1166*492ec93aSEd Tanous setDbusProperty(asyncResp, "RoleId", "xyz.openbmc_project.User.Manager", 1167*492ec93aSEd Tanous params.dbusObjectPath, 1168*492ec93aSEd Tanous "xyz.openbmc_project.User.Attributes", "UserPrivilege", 1169*492ec93aSEd Tanous priv); 11706c51eab1SEd Tanous } 11716c51eab1SEd Tanous 1172*492ec93aSEd Tanous if (params.locked) 11736c51eab1SEd Tanous { 11746c51eab1SEd Tanous // admin can unlock the account which is locked by 11756c51eab1SEd Tanous // successive authentication failures but admin should 11766c51eab1SEd Tanous // not be allowed to lock an account. 1177*492ec93aSEd Tanous if (*params.locked) 11786c51eab1SEd Tanous { 1179*492ec93aSEd Tanous messages::propertyValueNotInList(asyncResp->res, "true", "Locked"); 11806c51eab1SEd Tanous return; 11816c51eab1SEd Tanous } 1182*492ec93aSEd Tanous setDbusProperty(asyncResp, "Locked", "xyz.openbmc_project.User.Manager", 1183*492ec93aSEd Tanous params.dbusObjectPath, 1184*492ec93aSEd Tanous "xyz.openbmc_project.User.Attributes", 1185*492ec93aSEd Tanous "UserLockedForFailedAttempt", *params.locked); 11866c51eab1SEd Tanous } 118758345856SAbhishek Patel 1188*492ec93aSEd Tanous if (params.accountTypes) 118958345856SAbhishek Patel { 1190*492ec93aSEd Tanous patchAccountTypes(*params.accountTypes, asyncResp, 1191*492ec93aSEd Tanous params.dbusObjectPath, params.userSelf); 119258345856SAbhishek Patel } 1193*492ec93aSEd Tanous } 1194*492ec93aSEd Tanous 1195*492ec93aSEd Tanous inline void updateUserProperties( 1196*492ec93aSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1197*492ec93aSEd Tanous const std::string& username, const std::optional<std::string>& password, 1198*492ec93aSEd Tanous const std::optional<bool>& enabled, 1199*492ec93aSEd Tanous const std::optional<std::string>& roleId, const std::optional<bool>& locked, 1200*492ec93aSEd Tanous const std::optional<std::vector<std::string>>& accountTypes, bool userSelf, 1201*492ec93aSEd Tanous const std::shared_ptr<persistent_data::UserSession>& session) 1202*492ec93aSEd Tanous { 1203*492ec93aSEd Tanous sdbusplus::message::object_path tempObjPath(rootUserDbusPath); 1204*492ec93aSEd Tanous tempObjPath /= username; 1205*492ec93aSEd Tanous std::string dbusObjectPath(tempObjPath); 1206*492ec93aSEd Tanous 1207*492ec93aSEd Tanous UserUpdateParams params{username, password, enabled, 1208*492ec93aSEd Tanous roleId, locked, accountTypes, 1209*492ec93aSEd Tanous userSelf, session, dbusObjectPath}; 1210*492ec93aSEd Tanous 1211*492ec93aSEd Tanous dbus::utility::checkDbusPathExists( 1212*492ec93aSEd Tanous dbusObjectPath, 1213*492ec93aSEd Tanous std::bind_front(afterVerifyUserExists, asyncResp, std::move(params))); 12146c51eab1SEd Tanous } 12156c51eab1SEd Tanous 12164c7d4d33SEd Tanous inline void handleAccountServiceHead( 12174c7d4d33SEd Tanous App& app, const crow::Request& req, 12181ef4c342SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 12196c51eab1SEd Tanous { 12203ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 122145ca1b86SEd Tanous { 122245ca1b86SEd Tanous return; 122345ca1b86SEd Tanous } 12244c7d4d33SEd Tanous asyncResp->res.addHeader( 12254c7d4d33SEd Tanous boost::beast::http::field::link, 12264c7d4d33SEd Tanous "</redfish/v1/JsonSchemas/AccountService/AccountService.json>; rel=describedby"); 12274c7d4d33SEd Tanous } 12284c7d4d33SEd Tanous 12294c7d4d33SEd Tanous inline void 12301aa375b8SEd Tanous getClientCertificates(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 12311aa375b8SEd Tanous const nlohmann::json::json_pointer& keyLocation) 12321aa375b8SEd Tanous { 12331aa375b8SEd Tanous boost::urls::url url( 12341aa375b8SEd Tanous "/redfish/v1/AccountService/MultiFactorAuth/ClientCertificate/Certificates"); 12351aa375b8SEd Tanous std::array<std::string_view, 1> interfaces = { 12361aa375b8SEd Tanous "xyz.openbmc_project.Certs.Certificate"}; 12371aa375b8SEd Tanous std::string path = "/xyz/openbmc_project/certs/authority/truststore"; 12381aa375b8SEd Tanous 12391aa375b8SEd Tanous collection_util::getCollectionToKey(asyncResp, url, interfaces, path, 12401aa375b8SEd Tanous keyLocation); 12411aa375b8SEd Tanous } 12421aa375b8SEd Tanous 12431aa375b8SEd Tanous inline void handleAccountServiceClientCertificatesInstanceHead( 12441aa375b8SEd Tanous App& app, const crow::Request& req, 12451aa375b8SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 12461aa375b8SEd Tanous const std::string& /*id*/) 12471aa375b8SEd Tanous { 12481aa375b8SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 12491aa375b8SEd Tanous { 12501aa375b8SEd Tanous return; 12511aa375b8SEd Tanous } 12521aa375b8SEd Tanous 12531aa375b8SEd Tanous asyncResp->res.addHeader( 12541aa375b8SEd Tanous boost::beast::http::field::link, 12551aa375b8SEd Tanous "</redfish/v1/JsonSchemas/Certificate/Certificate.json>; rel=describedby"); 12561aa375b8SEd Tanous } 12571aa375b8SEd Tanous 12581aa375b8SEd Tanous inline void handleAccountServiceClientCertificatesInstanceGet( 12591aa375b8SEd Tanous App& app, const crow::Request& req, 12601aa375b8SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id) 12611aa375b8SEd Tanous { 12621aa375b8SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 12631aa375b8SEd Tanous { 12641aa375b8SEd Tanous return; 12651aa375b8SEd Tanous } 12661aa375b8SEd Tanous BMCWEB_LOG_DEBUG("ClientCertificate Certificate ID={}", id); 12671aa375b8SEd Tanous const boost::urls::url certURL = boost::urls::format( 12681aa375b8SEd Tanous "/redfish/v1/AccountService/MultiFactorAuth/ClientCertificate/Certificates/{}", 12691aa375b8SEd Tanous id); 12701aa375b8SEd Tanous std::string objPath = 12711aa375b8SEd Tanous sdbusplus::message::object_path(certs::authorityObjectPath) / id; 12721aa375b8SEd Tanous getCertificateProperties( 12731aa375b8SEd Tanous asyncResp, objPath, 12741aa375b8SEd Tanous "xyz.openbmc_project.Certs.Manager.Authority.Truststore", id, certURL, 12751aa375b8SEd Tanous "Client Certificate"); 12761aa375b8SEd Tanous } 12771aa375b8SEd Tanous 12781aa375b8SEd Tanous inline void handleAccountServiceClientCertificatesHead( 12791aa375b8SEd Tanous App& app, const crow::Request& req, 12801aa375b8SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 12811aa375b8SEd Tanous { 12821aa375b8SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 12831aa375b8SEd Tanous { 12841aa375b8SEd Tanous return; 12851aa375b8SEd Tanous } 12861aa375b8SEd Tanous 12871aa375b8SEd Tanous asyncResp->res.addHeader( 12881aa375b8SEd Tanous boost::beast::http::field::link, 12891aa375b8SEd Tanous "</redfish/v1/JsonSchemas/CertificateCollection/CertificateCollection.json>; rel=describedby"); 12901aa375b8SEd Tanous } 12911aa375b8SEd Tanous 12921aa375b8SEd Tanous inline void handleAccountServiceClientCertificatesGet( 12931aa375b8SEd Tanous App& app, const crow::Request& req, 12941aa375b8SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 12951aa375b8SEd Tanous { 12961aa375b8SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 12971aa375b8SEd Tanous { 12981aa375b8SEd Tanous return; 12991aa375b8SEd Tanous } 13001aa375b8SEd Tanous getClientCertificates(asyncResp, "/Members"_json_pointer); 13011aa375b8SEd Tanous } 13021aa375b8SEd Tanous 13033ce3688aSEd Tanous using account_service::CertificateMappingAttribute; 13043ce3688aSEd Tanous using persistent_data::MTLSCommonNameParseMode; 13053ce3688aSEd Tanous inline CertificateMappingAttribute 13063ce3688aSEd Tanous getCertificateMapping(MTLSCommonNameParseMode parse) 13073ce3688aSEd Tanous { 13083ce3688aSEd Tanous switch (parse) 13093ce3688aSEd Tanous { 13103ce3688aSEd Tanous case MTLSCommonNameParseMode::CommonName: 13113ce3688aSEd Tanous { 13123ce3688aSEd Tanous return CertificateMappingAttribute::CommonName; 13133ce3688aSEd Tanous } 13143ce3688aSEd Tanous break; 13153ce3688aSEd Tanous case MTLSCommonNameParseMode::Whole: 13163ce3688aSEd Tanous { 13173ce3688aSEd Tanous return CertificateMappingAttribute::Whole; 13183ce3688aSEd Tanous } 13193ce3688aSEd Tanous break; 13203ce3688aSEd Tanous case MTLSCommonNameParseMode::UserPrincipalName: 13213ce3688aSEd Tanous { 13223ce3688aSEd Tanous return CertificateMappingAttribute::UserPrincipalName; 13233ce3688aSEd Tanous } 13243ce3688aSEd Tanous break; 13253ce3688aSEd Tanous 13263ce3688aSEd Tanous case MTLSCommonNameParseMode::Meta: 13273ce3688aSEd Tanous { 13283ce3688aSEd Tanous if constexpr (BMCWEB_META_TLS_COMMON_NAME_PARSING) 13293ce3688aSEd Tanous { 13303ce3688aSEd Tanous return CertificateMappingAttribute::CommonName; 13313ce3688aSEd Tanous } 13323ce3688aSEd Tanous } 13333ce3688aSEd Tanous break; 13343ce3688aSEd Tanous default: 13353ce3688aSEd Tanous { 13363ce3688aSEd Tanous return CertificateMappingAttribute::Invalid; 13373ce3688aSEd Tanous } 13383ce3688aSEd Tanous break; 13393ce3688aSEd Tanous } 13403ce3688aSEd Tanous } 13413ce3688aSEd Tanous 13421aa375b8SEd Tanous inline void 13434c7d4d33SEd Tanous handleAccountServiceGet(App& app, const crow::Request& req, 13444c7d4d33SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 13454c7d4d33SEd Tanous { 1346afd369c6SJiaqing Zhao if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 1347afd369c6SJiaqing Zhao { 1348afd369c6SJiaqing Zhao return; 1349afd369c6SJiaqing Zhao } 13503e72c202SNinad Palsule 13513e72c202SNinad Palsule if (req.session == nullptr) 13523e72c202SNinad Palsule { 13533e72c202SNinad Palsule messages::internalError(asyncResp->res); 13543e72c202SNinad Palsule return; 13553e72c202SNinad Palsule } 13563e72c202SNinad Palsule 1357c1019828SEd Tanous const persistent_data::AuthConfigMethods& authMethodsConfig = 1358c1019828SEd Tanous persistent_data::SessionStore::getInstance().getAuthMethodsConfig(); 1359c1019828SEd Tanous 1360afd369c6SJiaqing Zhao asyncResp->res.addHeader( 1361afd369c6SJiaqing Zhao boost::beast::http::field::link, 1362afd369c6SJiaqing Zhao "</redfish/v1/JsonSchemas/AccountService/AccountService.json>; rel=describedby"); 1363afd369c6SJiaqing Zhao 13641476687dSEd Tanous nlohmann::json& json = asyncResp->res.jsonValue; 13651476687dSEd Tanous json["@odata.id"] = "/redfish/v1/AccountService"; 1366482a69e7SRavi Teja json["@odata.type"] = "#AccountService.v1_15_0.AccountService"; 13671476687dSEd Tanous json["Id"] = "AccountService"; 13681476687dSEd Tanous json["Name"] = "Account Service"; 13691476687dSEd Tanous json["Description"] = "Account Service"; 13701476687dSEd Tanous json["ServiceEnabled"] = true; 13711476687dSEd Tanous json["MaxPasswordLength"] = 20; 13721ef4c342SEd Tanous json["Accounts"]["@odata.id"] = "/redfish/v1/AccountService/Accounts"; 13731476687dSEd Tanous json["Roles"]["@odata.id"] = "/redfish/v1/AccountService/Roles"; 1374482a69e7SRavi Teja json["HTTPBasicAuth"] = authMethodsConfig.basic 1375482a69e7SRavi Teja ? account_service::BasicAuthState::Enabled 1376482a69e7SRavi Teja : account_service::BasicAuthState::Disabled; 1377482a69e7SRavi Teja 1378482a69e7SRavi Teja nlohmann::json::array_t allowed; 1379482a69e7SRavi Teja allowed.emplace_back(account_service::BasicAuthState::Enabled); 1380482a69e7SRavi Teja allowed.emplace_back(account_service::BasicAuthState::Disabled); 1381482a69e7SRavi Teja json["HTTPBasicAuth@AllowableValues"] = std::move(allowed); 1382482a69e7SRavi Teja 13831aa375b8SEd Tanous nlohmann::json::object_t clientCertificate; 13841aa375b8SEd Tanous clientCertificate["Enabled"] = authMethodsConfig.tls; 13853281bcf1SEd Tanous clientCertificate["RespondToUnauthenticatedClients"] = 13863281bcf1SEd Tanous !authMethodsConfig.tlsStrict; 13873ce3688aSEd Tanous 13883ce3688aSEd Tanous using account_service::CertificateMappingAttribute; 13893ce3688aSEd Tanous 13903ce3688aSEd Tanous CertificateMappingAttribute mapping = 13913ce3688aSEd Tanous getCertificateMapping(authMethodsConfig.mTLSCommonNameParsingMode); 13923ce3688aSEd Tanous if (mapping == CertificateMappingAttribute::Invalid) 13933ce3688aSEd Tanous { 13943ce3688aSEd Tanous messages::internalError(asyncResp->res); 13953ce3688aSEd Tanous } 13963ce3688aSEd Tanous else 13973ce3688aSEd Tanous { 13983ce3688aSEd Tanous clientCertificate["CertificateMappingAttribute"] = mapping; 13993ce3688aSEd Tanous } 14001aa375b8SEd Tanous nlohmann::json::object_t certificates; 14011aa375b8SEd Tanous certificates["@odata.id"] = 14021aa375b8SEd Tanous "/redfish/v1/AccountService/MultiFactorAuth/ClientCertificate/Certificates"; 14031aa375b8SEd Tanous certificates["@odata.type"] = 14041aa375b8SEd Tanous "#CertificateCollection.CertificateCollection"; 14051aa375b8SEd Tanous clientCertificate["Certificates"] = std::move(certificates); 14061aa375b8SEd Tanous json["MultiFactorAuth"]["ClientCertificate"] = std::move(clientCertificate); 14071aa375b8SEd Tanous 14081aa375b8SEd Tanous getClientCertificates( 14091aa375b8SEd Tanous asyncResp, 14101aa375b8SEd Tanous "/MultiFactorAuth/ClientCertificate/Certificates/Members"_json_pointer); 14111aa375b8SEd Tanous 14121476687dSEd Tanous json["Oem"]["OpenBMC"]["@odata.type"] = 14135b5574acSEd Tanous "#OpenBMCAccountService.v1_0_0.AccountService"; 14141476687dSEd Tanous json["Oem"]["OpenBMC"]["@odata.id"] = 14151476687dSEd Tanous "/redfish/v1/AccountService#/Oem/OpenBMC"; 14161476687dSEd Tanous json["Oem"]["OpenBMC"]["AuthMethods"]["BasicAuth"] = 14171476687dSEd Tanous authMethodsConfig.basic; 14181476687dSEd Tanous json["Oem"]["OpenBMC"]["AuthMethods"]["SessionToken"] = 14191476687dSEd Tanous authMethodsConfig.sessionToken; 14201ef4c342SEd Tanous json["Oem"]["OpenBMC"]["AuthMethods"]["XToken"] = authMethodsConfig.xtoken; 14211ef4c342SEd Tanous json["Oem"]["OpenBMC"]["AuthMethods"]["Cookie"] = authMethodsConfig.cookie; 14221ef4c342SEd Tanous json["Oem"]["OpenBMC"]["AuthMethods"]["TLS"] = authMethodsConfig.tls; 14231476687dSEd Tanous 14241ef4c342SEd Tanous // /redfish/v1/AccountService/LDAP/Certificates is something only 14251ef4c342SEd Tanous // ConfigureManager can access then only display when the user has 14261ef4c342SEd Tanous // permissions ConfigureManager 142772048780SAbhishek Patel Privileges effectiveUserPrivileges = 14283e72c202SNinad Palsule redfish::getUserPrivileges(*req.session); 142972048780SAbhishek Patel 143072048780SAbhishek Patel if (isOperationAllowedWithPrivileges({{"ConfigureManager"}}, 143172048780SAbhishek Patel effectiveUserPrivileges)) 143272048780SAbhishek Patel { 14331ef4c342SEd Tanous asyncResp->res.jsonValue["LDAP"]["Certificates"]["@odata.id"] = 14341476687dSEd Tanous "/redfish/v1/AccountService/LDAP/Certificates"; 143572048780SAbhishek Patel } 1436deae6a78SEd Tanous dbus::utility::getAllProperties( 1437deae6a78SEd Tanous "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user", 1438deae6a78SEd Tanous "xyz.openbmc_project.User.AccountPolicy", 14395e7e2dc5SEd Tanous [asyncResp](const boost::system::error_code& ec, 14401ef4c342SEd Tanous const dbus::utility::DBusPropertiesMap& propertiesList) { 14413d958bbcSAppaRao Puli if (ec) 14423d958bbcSAppaRao Puli { 14433d958bbcSAppaRao Puli messages::internalError(asyncResp->res); 14443d958bbcSAppaRao Puli return; 14453d958bbcSAppaRao Puli } 1446d1bde9e5SKrzysztof Grobelny 144762598e31SEd Tanous BMCWEB_LOG_DEBUG("Got {} properties for AccountService", 144862598e31SEd Tanous propertiesList.size()); 1449d1bde9e5SKrzysztof Grobelny 1450d1bde9e5SKrzysztof Grobelny const uint8_t* minPasswordLength = nullptr; 1451d1bde9e5SKrzysztof Grobelny const uint32_t* accountUnlockTimeout = nullptr; 1452d1bde9e5SKrzysztof Grobelny const uint16_t* maxLoginAttemptBeforeLockout = nullptr; 1453d1bde9e5SKrzysztof Grobelny 1454d1bde9e5SKrzysztof Grobelny const bool success = sdbusplus::unpackPropertiesNoThrow( 1455d1bde9e5SKrzysztof Grobelny dbus_utils::UnpackErrorPrinter(), propertiesList, 1456d1bde9e5SKrzysztof Grobelny "MinPasswordLength", minPasswordLength, "AccountUnlockTimeout", 1457d1bde9e5SKrzysztof Grobelny accountUnlockTimeout, "MaxLoginAttemptBeforeLockout", 1458d1bde9e5SKrzysztof Grobelny maxLoginAttemptBeforeLockout); 1459d1bde9e5SKrzysztof Grobelny 1460d1bde9e5SKrzysztof Grobelny if (!success) 14613d958bbcSAppaRao Puli { 1462d1bde9e5SKrzysztof Grobelny messages::internalError(asyncResp->res); 1463d1bde9e5SKrzysztof Grobelny return; 14643d958bbcSAppaRao Puli } 1465d1bde9e5SKrzysztof Grobelny 1466d1bde9e5SKrzysztof Grobelny if (minPasswordLength != nullptr) 14673d958bbcSAppaRao Puli { 1468bd79bce8SPatrick Williams asyncResp->res.jsonValue["MinPasswordLength"] = 1469bd79bce8SPatrick Williams *minPasswordLength; 14703d958bbcSAppaRao Puli } 1471d1bde9e5SKrzysztof Grobelny 1472d1bde9e5SKrzysztof Grobelny if (accountUnlockTimeout != nullptr) 14733d958bbcSAppaRao Puli { 1474d1bde9e5SKrzysztof Grobelny asyncResp->res.jsonValue["AccountLockoutDuration"] = 1475d1bde9e5SKrzysztof Grobelny *accountUnlockTimeout; 1476d1bde9e5SKrzysztof Grobelny } 1477d1bde9e5SKrzysztof Grobelny 1478d1bde9e5SKrzysztof Grobelny if (maxLoginAttemptBeforeLockout != nullptr) 14793d958bbcSAppaRao Puli { 1480002d39b4SEd Tanous asyncResp->res.jsonValue["AccountLockoutThreshold"] = 1481d1bde9e5SKrzysztof Grobelny *maxLoginAttemptBeforeLockout; 14823d958bbcSAppaRao Puli } 1483d1bde9e5SKrzysztof Grobelny }); 14846973a582SRatan Gupta 148502cad96eSEd Tanous auto callback = [asyncResp](bool success, const LDAPConfigData& confData, 1486ab828d7cSRatan Gupta const std::string& ldapType) { 1487cb13a392SEd Tanous if (!success) 1488cb13a392SEd Tanous { 1489cb13a392SEd Tanous return; 1490cb13a392SEd Tanous } 1491002d39b4SEd Tanous parseLDAPConfigData(asyncResp->res.jsonValue, confData, ldapType); 1492ab828d7cSRatan Gupta }; 1493ab828d7cSRatan Gupta 1494ab828d7cSRatan Gupta getLDAPConfigData("LDAP", callback); 1495ab828d7cSRatan Gupta getLDAPConfigData("ActiveDirectory", callback); 14961ef4c342SEd Tanous } 14976973a582SRatan Gupta 1498bd79bce8SPatrick Williams inline void handleCertificateMappingAttributePatch( 1499bd79bce8SPatrick Williams crow::Response& res, const std::string& certMapAttribute) 15003ce3688aSEd Tanous { 15013ce3688aSEd Tanous MTLSCommonNameParseMode parseMode = 15023ce3688aSEd Tanous persistent_data::getMTLSCommonNameParseMode(certMapAttribute); 15033ce3688aSEd Tanous if (parseMode == MTLSCommonNameParseMode::Invalid) 15043ce3688aSEd Tanous { 15053ce3688aSEd Tanous messages::propertyValueNotInList(res, "CertificateMappingAttribute", 15063ce3688aSEd Tanous certMapAttribute); 15073ce3688aSEd Tanous return; 15083ce3688aSEd Tanous } 15093ce3688aSEd Tanous 15103ce3688aSEd Tanous persistent_data::AuthConfigMethods& authMethodsConfig = 15113ce3688aSEd Tanous persistent_data::SessionStore::getInstance().getAuthMethodsConfig(); 15123ce3688aSEd Tanous authMethodsConfig.mTLSCommonNameParsingMode = parseMode; 15133ce3688aSEd Tanous } 15143ce3688aSEd Tanous 15153281bcf1SEd Tanous inline void handleRespondToUnauthenticatedClientsPatch( 15163281bcf1SEd Tanous App& app, const crow::Request& req, crow::Response& res, 15173281bcf1SEd Tanous bool respondToUnauthenticatedClients) 15183281bcf1SEd Tanous { 15193281bcf1SEd Tanous if (req.session != nullptr) 15203281bcf1SEd Tanous { 15213281bcf1SEd Tanous // Sanity check. If the user isn't currently authenticated with mutual 15223281bcf1SEd Tanous // TLS, they very likely are about to permanently lock themselves out. 15233281bcf1SEd Tanous // Make sure they're using mutual TLS before allowing locking. 15243281bcf1SEd Tanous if (req.session->sessionType != persistent_data::SessionType::MutualTLS) 15253281bcf1SEd Tanous { 15263281bcf1SEd Tanous messages::propertyValueExternalConflict( 15273281bcf1SEd Tanous res, 15283281bcf1SEd Tanous "MultiFactorAuth/ClientCertificate/RespondToUnauthenticatedClients", 15293281bcf1SEd Tanous respondToUnauthenticatedClients); 15303281bcf1SEd Tanous return; 15313281bcf1SEd Tanous } 15323281bcf1SEd Tanous } 15333281bcf1SEd Tanous 15343281bcf1SEd Tanous persistent_data::AuthConfigMethods& authMethodsConfig = 15353281bcf1SEd Tanous persistent_data::SessionStore::getInstance().getAuthMethodsConfig(); 15363281bcf1SEd Tanous 15373281bcf1SEd Tanous // Change the settings 15383281bcf1SEd Tanous authMethodsConfig.tlsStrict = !respondToUnauthenticatedClients; 15393281bcf1SEd Tanous 15403281bcf1SEd Tanous // Write settings to disk 15413281bcf1SEd Tanous persistent_data::getConfig().writeData(); 15423281bcf1SEd Tanous 15433281bcf1SEd Tanous // Trigger a reload, to apply the new settings to new connections 15443281bcf1SEd Tanous app.loadCertificate(); 15453281bcf1SEd Tanous } 15463281bcf1SEd Tanous 15471ef4c342SEd Tanous inline void handleAccountServicePatch( 15481ef4c342SEd Tanous App& app, const crow::Request& req, 15491ef4c342SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 15501ef4c342SEd Tanous { 15513ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 155245ca1b86SEd Tanous { 155345ca1b86SEd Tanous return; 155445ca1b86SEd Tanous } 1555f5ffd806SEd Tanous std::optional<uint32_t> unlockTimeout; 1556f5ffd806SEd Tanous std::optional<uint16_t> lockoutThreshold; 1557ef73ad0dSPaul Fertser std::optional<uint8_t> minPasswordLength; 1558f5ffd806SEd Tanous std::optional<uint16_t> maxPasswordLength; 155910cb44f3SEd Tanous LdapPatchParams ldapObject; 15603ce3688aSEd Tanous std::optional<std::string> certificateMappingAttribute; 15613281bcf1SEd Tanous std::optional<bool> respondToUnauthenticatedClients; 156210cb44f3SEd Tanous LdapPatchParams activeDirectoryObject; 1563c1019828SEd Tanous AuthMethods auth; 1564482a69e7SRavi Teja std::optional<std::string> httpBasicAuth; 15653ce3688aSEd Tanous 1566afc474aeSMyung Bae if (!json_util::readJsonPatch( // 1567afc474aeSMyung Bae req, asyncResp->res, // 1568afc474aeSMyung Bae "AccountLockoutDuration", unlockTimeout, // 1569afc474aeSMyung Bae "AccountLockoutThreshold", lockoutThreshold, // 1570afc474aeSMyung Bae "ActiveDirectory/Authentication/AuthenticationType", 1571afc474aeSMyung Bae activeDirectoryObject.authType, // 1572afc474aeSMyung Bae "ActiveDirectory/Authentication/Password", 1573afc474aeSMyung Bae activeDirectoryObject.password, // 1574afc474aeSMyung Bae "ActiveDirectory/Authentication/Username", 1575afc474aeSMyung Bae activeDirectoryObject.userName, // 1576afc474aeSMyung Bae "ActiveDirectory/LDAPService/SearchSettings/BaseDistinguishedNames", 1577afc474aeSMyung Bae activeDirectoryObject.baseDNList, // 1578afc474aeSMyung Bae "ActiveDirectory/LDAPService/SearchSettings/GroupsAttribute", 1579afc474aeSMyung Bae activeDirectoryObject.groupsAttribute, // 1580afc474aeSMyung Bae "ActiveDirectory/LDAPService/SearchSettings/UsernameAttribute", 1581afc474aeSMyung Bae activeDirectoryObject.userNameAttribute, // 1582afc474aeSMyung Bae "ActiveDirectory/RemoteRoleMapping", 1583afc474aeSMyung Bae activeDirectoryObject.remoteRoleMapData, // 1584afc474aeSMyung Bae "ActiveDirectory/ServiceAddresses", 1585afc474aeSMyung Bae activeDirectoryObject.serviceAddressList, // 1586afc474aeSMyung Bae "ActiveDirectory/ServiceEnabled", 1587afc474aeSMyung Bae activeDirectoryObject.serviceEnabled, // 1588afc474aeSMyung Bae "HTTPBasicAuth", httpBasicAuth, // 1589afc474aeSMyung Bae "LDAP/Authentication/AuthenticationType", ldapObject.authType, // 1590afc474aeSMyung Bae "LDAP/Authentication/Password", ldapObject.password, // 1591afc474aeSMyung Bae "LDAP/Authentication/Username", ldapObject.userName, // 1592afc474aeSMyung Bae "LDAP/LDAPService/SearchSettings/BaseDistinguishedNames", 1593afc474aeSMyung Bae ldapObject.baseDNList, // 1594afc474aeSMyung Bae "LDAP/LDAPService/SearchSettings/GroupsAttribute", 1595afc474aeSMyung Bae ldapObject.groupsAttribute, // 1596afc474aeSMyung Bae "LDAP/LDAPService/SearchSettings/UsernameAttribute", 1597afc474aeSMyung Bae ldapObject.userNameAttribute, // 1598afc474aeSMyung Bae "LDAP/RemoteRoleMapping", ldapObject.remoteRoleMapData, // 1599afc474aeSMyung Bae "LDAP/ServiceAddresses", ldapObject.serviceAddressList, // 1600afc474aeSMyung Bae "LDAP/ServiceEnabled", ldapObject.serviceEnabled, // 1601afc474aeSMyung Bae "MaxPasswordLength", maxPasswordLength, // 1602afc474aeSMyung Bae "MinPasswordLength", minPasswordLength, // 1603afc474aeSMyung Bae "MultiFactorAuth/ClientCertificate/CertificateMappingAttribute", 1604afc474aeSMyung Bae certificateMappingAttribute, // 1605afc474aeSMyung Bae "MultiFactorAuth/ClientCertificate/RespondToUnauthenticatedClients", 1606afc474aeSMyung Bae respondToUnauthenticatedClients, // 1607afc474aeSMyung Bae "Oem/OpenBMC/AuthMethods/BasicAuth", auth.basicAuth, // 1608afc474aeSMyung Bae "Oem/OpenBMC/AuthMethods/Cookie", auth.cookie, // 1609afc474aeSMyung Bae "Oem/OpenBMC/AuthMethods/SessionToken", auth.sessionToken, // 1610afc474aeSMyung Bae "Oem/OpenBMC/AuthMethods/TLS", auth.tls, // 1611afc474aeSMyung Bae "Oem/OpenBMC/AuthMethods/XToken", auth.xToken // 1612afc474aeSMyung Bae )) 1613f5ffd806SEd Tanous { 1614f5ffd806SEd Tanous return; 1615f5ffd806SEd Tanous } 1616f5ffd806SEd Tanous 1617482a69e7SRavi Teja if (httpBasicAuth) 1618482a69e7SRavi Teja { 1619482a69e7SRavi Teja if (*httpBasicAuth == "Enabled") 1620482a69e7SRavi Teja { 1621482a69e7SRavi Teja auth.basicAuth = true; 1622482a69e7SRavi Teja } 1623482a69e7SRavi Teja else if (*httpBasicAuth == "Disabled") 1624482a69e7SRavi Teja { 1625482a69e7SRavi Teja auth.basicAuth = false; 1626482a69e7SRavi Teja } 1627482a69e7SRavi Teja else 1628482a69e7SRavi Teja { 1629482a69e7SRavi Teja messages::propertyValueNotInList(asyncResp->res, "HttpBasicAuth", 1630482a69e7SRavi Teja *httpBasicAuth); 1631482a69e7SRavi Teja } 1632482a69e7SRavi Teja } 1633482a69e7SRavi Teja 16343281bcf1SEd Tanous if (respondToUnauthenticatedClients) 16353281bcf1SEd Tanous { 16363281bcf1SEd Tanous handleRespondToUnauthenticatedClientsPatch( 16373281bcf1SEd Tanous app, req, asyncResp->res, *respondToUnauthenticatedClients); 16383281bcf1SEd Tanous } 16393281bcf1SEd Tanous 16403ce3688aSEd Tanous if (certificateMappingAttribute) 16413ce3688aSEd Tanous { 16423ce3688aSEd Tanous handleCertificateMappingAttributePatch(asyncResp->res, 16433ce3688aSEd Tanous *certificateMappingAttribute); 16443ce3688aSEd Tanous } 16453ce3688aSEd Tanous 1646f5ffd806SEd Tanous if (minPasswordLength) 1647f5ffd806SEd Tanous { 1648d02aad39SEd Tanous setDbusProperty( 1649e93abac6SGinu George asyncResp, "MinPasswordLength", "xyz.openbmc_project.User.Manager", 1650d02aad39SEd Tanous sdbusplus::message::object_path("/xyz/openbmc_project/user"), 16519ae226faSGeorge Liu "xyz.openbmc_project.User.AccountPolicy", "MinPasswordLength", 1652e93abac6SGinu George *minPasswordLength); 1653f5ffd806SEd Tanous } 1654f5ffd806SEd Tanous 1655f5ffd806SEd Tanous if (maxPasswordLength) 1656f5ffd806SEd Tanous { 16571ef4c342SEd Tanous messages::propertyNotWritable(asyncResp->res, "MaxPasswordLength"); 1658f5ffd806SEd Tanous } 1659f5ffd806SEd Tanous 166010cb44f3SEd Tanous handleLDAPPatch(std::move(activeDirectoryObject), asyncResp, 166110cb44f3SEd Tanous "ActiveDirectory"); 166210cb44f3SEd Tanous handleLDAPPatch(std::move(ldapObject), asyncResp, "LDAP"); 1663f5ffd806SEd Tanous 1664c1019828SEd Tanous handleAuthMethodsPatch(asyncResp, auth); 1665f5ffd806SEd Tanous 1666f5ffd806SEd Tanous if (unlockTimeout) 1667f5ffd806SEd Tanous { 1668d02aad39SEd Tanous setDbusProperty( 1669e93abac6SGinu George asyncResp, "AccountLockoutDuration", 1670e93abac6SGinu George "xyz.openbmc_project.User.Manager", 1671d02aad39SEd Tanous sdbusplus::message::object_path("/xyz/openbmc_project/user"), 16729ae226faSGeorge Liu "xyz.openbmc_project.User.AccountPolicy", "AccountUnlockTimeout", 1673e93abac6SGinu George *unlockTimeout); 1674f5ffd806SEd Tanous } 1675f5ffd806SEd Tanous if (lockoutThreshold) 1676f5ffd806SEd Tanous { 1677d02aad39SEd Tanous setDbusProperty( 1678e93abac6SGinu George asyncResp, "AccountLockoutThreshold", 1679e93abac6SGinu George "xyz.openbmc_project.User.Manager", 1680d02aad39SEd Tanous sdbusplus::message::object_path("/xyz/openbmc_project/user"), 16819ae226faSGeorge Liu "xyz.openbmc_project.User.AccountPolicy", 1682e93abac6SGinu George "MaxLoginAttemptBeforeLockout", *lockoutThreshold); 1683f5ffd806SEd Tanous } 16841ef4c342SEd Tanous } 1685f5ffd806SEd Tanous 16864c7d4d33SEd Tanous inline void handleAccountCollectionHead( 16871ef4c342SEd Tanous App& app, const crow::Request& req, 16881ef4c342SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 16891ef4c342SEd Tanous { 16903ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 169145ca1b86SEd Tanous { 169245ca1b86SEd Tanous return; 169345ca1b86SEd Tanous } 16944c7d4d33SEd Tanous asyncResp->res.addHeader( 16954c7d4d33SEd Tanous boost::beast::http::field::link, 16964c7d4d33SEd Tanous "</redfish/v1/JsonSchemas/ManagerAccountCollection.json>; rel=describedby"); 16974c7d4d33SEd Tanous } 16984c7d4d33SEd Tanous 16994c7d4d33SEd Tanous inline void handleAccountCollectionGet( 17004c7d4d33SEd Tanous App& app, const crow::Request& req, 17014c7d4d33SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 17024c7d4d33SEd Tanous { 1703afd369c6SJiaqing Zhao if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 1704afd369c6SJiaqing Zhao { 1705afd369c6SJiaqing Zhao return; 1706afd369c6SJiaqing Zhao } 17073e72c202SNinad Palsule 17083e72c202SNinad Palsule if (req.session == nullptr) 17093e72c202SNinad Palsule { 17103e72c202SNinad Palsule messages::internalError(asyncResp->res); 17113e72c202SNinad Palsule return; 17123e72c202SNinad Palsule } 17133e72c202SNinad Palsule 1714afd369c6SJiaqing Zhao asyncResp->res.addHeader( 1715afd369c6SJiaqing Zhao boost::beast::http::field::link, 1716afd369c6SJiaqing Zhao "</redfish/v1/JsonSchemas/ManagerAccountCollection.json>; rel=describedby"); 17171476687dSEd Tanous 17181476687dSEd Tanous asyncResp->res.jsonValue["@odata.id"] = 17191476687dSEd Tanous "/redfish/v1/AccountService/Accounts"; 17201ef4c342SEd Tanous asyncResp->res.jsonValue["@odata.type"] = "#ManagerAccountCollection." 17211476687dSEd Tanous "ManagerAccountCollection"; 17221476687dSEd Tanous asyncResp->res.jsonValue["Name"] = "Accounts Collection"; 17231476687dSEd Tanous asyncResp->res.jsonValue["Description"] = "BMC User Accounts"; 17240f74e643SEd Tanous 17256c51eab1SEd Tanous Privileges effectiveUserPrivileges = 17263e72c202SNinad Palsule redfish::getUserPrivileges(*req.session); 17276c51eab1SEd Tanous 1728f5e29f33SJunLin Chen std::string thisUser; 1729f5e29f33SJunLin Chen if (req.session) 1730f5e29f33SJunLin Chen { 1731f5e29f33SJunLin Chen thisUser = req.session->username; 1732f5e29f33SJunLin Chen } 17335eb468daSGeorge Liu sdbusplus::message::object_path path("/xyz/openbmc_project/user"); 17345eb468daSGeorge Liu dbus::utility::getManagedObjects( 17355eb468daSGeorge Liu "xyz.openbmc_project.User.Manager", path, 1736cef1ddfbSEd Tanous [asyncResp, thisUser, effectiveUserPrivileges]( 17375e7e2dc5SEd Tanous const boost::system::error_code& ec, 1738711ac7a9SEd Tanous const dbus::utility::ManagedObjectType& users) { 1739b9b2e0b2SEd Tanous if (ec) 1740b9b2e0b2SEd Tanous { 1741f12894f8SJason M. Bills messages::internalError(asyncResp->res); 1742b9b2e0b2SEd Tanous return; 1743b9b2e0b2SEd Tanous } 1744b9b2e0b2SEd Tanous 1745cef1ddfbSEd Tanous bool userCanSeeAllAccounts = 1746002d39b4SEd Tanous effectiveUserPrivileges.isSupersetOf({"ConfigureUsers"}); 1747cef1ddfbSEd Tanous 1748cef1ddfbSEd Tanous bool userCanSeeSelf = 1749002d39b4SEd Tanous effectiveUserPrivileges.isSupersetOf({"ConfigureSelf"}); 1750cef1ddfbSEd Tanous 1751002d39b4SEd Tanous nlohmann::json& memberArray = asyncResp->res.jsonValue["Members"]; 1752b9b2e0b2SEd Tanous memberArray = nlohmann::json::array(); 1753b9b2e0b2SEd Tanous 17549eb808c1SEd Tanous for (const auto& userpath : users) 1755b9b2e0b2SEd Tanous { 17562dfd18efSEd Tanous std::string user = userpath.first.filename(); 17572dfd18efSEd Tanous if (user.empty()) 1758b9b2e0b2SEd Tanous { 17592dfd18efSEd Tanous messages::internalError(asyncResp->res); 176062598e31SEd Tanous BMCWEB_LOG_ERROR("Invalid firmware ID"); 17612dfd18efSEd Tanous 17622dfd18efSEd Tanous return; 1763b9b2e0b2SEd Tanous } 1764f365910cSGunnar Mills 1765f365910cSGunnar Mills // As clarified by Redfish here: 1766f365910cSGunnar Mills // https://redfishforum.com/thread/281/manageraccountcollection-change-allows-account-enumeration 17676c51eab1SEd Tanous // Users without ConfigureUsers, only see their own 17686c51eab1SEd Tanous // account. Users with ConfigureUsers, see all 17696c51eab1SEd Tanous // accounts. 1770bd79bce8SPatrick Williams if (userCanSeeAllAccounts || 1771bd79bce8SPatrick Williams (thisUser == user && userCanSeeSelf)) 1772f365910cSGunnar Mills { 17731476687dSEd Tanous nlohmann::json::object_t member; 17743b32780dSEd Tanous member["@odata.id"] = boost::urls::format( 17753b32780dSEd Tanous "/redfish/v1/AccountService/Accounts/{}", user); 1776b2ba3072SPatrick Williams memberArray.emplace_back(std::move(member)); 1777b9b2e0b2SEd Tanous } 1778f365910cSGunnar Mills } 1779bd79bce8SPatrick Williams asyncResp->res.jsonValue["Members@odata.count"] = 1780bd79bce8SPatrick Williams memberArray.size(); 17815eb468daSGeorge Liu }); 17821ef4c342SEd Tanous } 17836c51eab1SEd Tanous 178497e90da3SNinad Palsule inline void processAfterCreateUser( 178597e90da3SNinad Palsule const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 178697e90da3SNinad Palsule const std::string& username, const std::string& password, 178797e90da3SNinad Palsule const boost::system::error_code& ec, sdbusplus::message_t& m) 178897e90da3SNinad Palsule { 178997e90da3SNinad Palsule if (ec) 179097e90da3SNinad Palsule { 179197e90da3SNinad Palsule userErrorMessageHandler(m.get_error(), asyncResp, username, ""); 179297e90da3SNinad Palsule return; 179397e90da3SNinad Palsule } 179497e90da3SNinad Palsule 179597e90da3SNinad Palsule if (pamUpdatePassword(username, password) != PAM_SUCCESS) 179697e90da3SNinad Palsule { 179797e90da3SNinad Palsule // At this point we have a user that's been 179897e90da3SNinad Palsule // created, but the password set 179997e90da3SNinad Palsule // failed.Something is wrong, so delete the user 180097e90da3SNinad Palsule // that we've already created 180197e90da3SNinad Palsule sdbusplus::message::object_path tempObjPath(rootUserDbusPath); 180297e90da3SNinad Palsule tempObjPath /= username; 180397e90da3SNinad Palsule const std::string userPath(tempObjPath); 180497e90da3SNinad Palsule 180597e90da3SNinad Palsule crow::connections::systemBus->async_method_call( 180697e90da3SNinad Palsule [asyncResp, password](const boost::system::error_code& ec3) { 180797e90da3SNinad Palsule if (ec3) 180897e90da3SNinad Palsule { 180997e90da3SNinad Palsule messages::internalError(asyncResp->res); 181097e90da3SNinad Palsule return; 181197e90da3SNinad Palsule } 181297e90da3SNinad Palsule 181397e90da3SNinad Palsule // If password is invalid 18149bd80831SJason M. Bills messages::propertyValueFormatError(asyncResp->res, nullptr, 181597e90da3SNinad Palsule "Password"); 181697e90da3SNinad Palsule }, 181797e90da3SNinad Palsule "xyz.openbmc_project.User.Manager", userPath, 181897e90da3SNinad Palsule "xyz.openbmc_project.Object.Delete", "Delete"); 181997e90da3SNinad Palsule 182062598e31SEd Tanous BMCWEB_LOG_ERROR("pamUpdatePassword Failed"); 182197e90da3SNinad Palsule return; 182297e90da3SNinad Palsule } 182397e90da3SNinad Palsule 182497e90da3SNinad Palsule messages::created(asyncResp->res); 182597e90da3SNinad Palsule asyncResp->res.addHeader("Location", 182697e90da3SNinad Palsule "/redfish/v1/AccountService/Accounts/" + username); 182797e90da3SNinad Palsule } 182897e90da3SNinad Palsule 182997e90da3SNinad Palsule inline void processAfterGetAllGroups( 183097e90da3SNinad Palsule const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 183197e90da3SNinad Palsule const std::string& username, const std::string& password, 1832e01d0c36SEd Tanous const std::string& roleId, bool enabled, 18339ba73934SNinad Palsule std::optional<std::vector<std::string>> accountTypes, 183497e90da3SNinad Palsule const std::vector<std::string>& allGroupsList) 183597e90da3SNinad Palsule { 18363e72c202SNinad Palsule std::vector<std::string> userGroups; 18379ba73934SNinad Palsule std::vector<std::string> accountTypeUserGroups; 18389ba73934SNinad Palsule 18399ba73934SNinad Palsule // If user specified account types then convert them to unix user groups 18409ba73934SNinad Palsule if (accountTypes) 18419ba73934SNinad Palsule { 18429ba73934SNinad Palsule if (!getUserGroupFromAccountType(asyncResp->res, *accountTypes, 18439ba73934SNinad Palsule accountTypeUserGroups)) 18449ba73934SNinad Palsule { 18459ba73934SNinad Palsule // Problem in mapping Account Types to User Groups, Error already 18469ba73934SNinad Palsule // logged. 18479ba73934SNinad Palsule return; 18489ba73934SNinad Palsule } 18499ba73934SNinad Palsule } 18509ba73934SNinad Palsule 18513e72c202SNinad Palsule for (const auto& grp : allGroupsList) 18523e72c202SNinad Palsule { 18539ba73934SNinad Palsule // If user specified the account type then only accept groups which are 18549ba73934SNinad Palsule // in the account types group list. 18559ba73934SNinad Palsule if (!accountTypeUserGroups.empty()) 18569ba73934SNinad Palsule { 18579ba73934SNinad Palsule bool found = false; 18589ba73934SNinad Palsule for (const auto& grp1 : accountTypeUserGroups) 18599ba73934SNinad Palsule { 18609ba73934SNinad Palsule if (grp == grp1) 18619ba73934SNinad Palsule { 18629ba73934SNinad Palsule found = true; 18639ba73934SNinad Palsule break; 18649ba73934SNinad Palsule } 18659ba73934SNinad Palsule } 18669ba73934SNinad Palsule if (!found) 18679ba73934SNinad Palsule { 18689ba73934SNinad Palsule continue; 18699ba73934SNinad Palsule } 18709ba73934SNinad Palsule } 18719ba73934SNinad Palsule 18723e72c202SNinad Palsule // Console access is provided to the user who is a member of 18733e72c202SNinad Palsule // hostconsole group and has a administrator role. So, set 18743e72c202SNinad Palsule // hostconsole group only for the administrator. 18759ba73934SNinad Palsule if ((grp == "hostconsole") && (roleId != "priv-admin")) 18763e72c202SNinad Palsule { 18779ba73934SNinad Palsule if (!accountTypeUserGroups.empty()) 18789ba73934SNinad Palsule { 187962598e31SEd Tanous BMCWEB_LOG_ERROR( 188062598e31SEd Tanous "Only administrator can get HostConsole access"); 18819ba73934SNinad Palsule asyncResp->res.result(boost::beast::http::status::bad_request); 18829ba73934SNinad Palsule return; 18839ba73934SNinad Palsule } 18849ba73934SNinad Palsule continue; 18859ba73934SNinad Palsule } 18863e72c202SNinad Palsule userGroups.emplace_back(grp); 18873e72c202SNinad Palsule } 18889ba73934SNinad Palsule 18899ba73934SNinad Palsule // Make sure user specified groups are valid. This is internal error because 18909ba73934SNinad Palsule // it some inconsistencies between user manager and bmcweb. 18919ba73934SNinad Palsule if (!accountTypeUserGroups.empty() && 18929ba73934SNinad Palsule accountTypeUserGroups.size() != userGroups.size()) 18939ba73934SNinad Palsule { 18949ba73934SNinad Palsule messages::internalError(asyncResp->res); 18959ba73934SNinad Palsule return; 18963e72c202SNinad Palsule } 189797e90da3SNinad Palsule crow::connections::systemBus->async_method_call( 189897e90da3SNinad Palsule [asyncResp, username, password](const boost::system::error_code& ec2, 189997e90da3SNinad Palsule sdbusplus::message_t& m) { 190097e90da3SNinad Palsule processAfterCreateUser(asyncResp, username, password, ec2, m); 190197e90da3SNinad Palsule }, 190297e90da3SNinad Palsule "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user", 19033e72c202SNinad Palsule "xyz.openbmc_project.User.Manager", "CreateUser", username, userGroups, 1904e01d0c36SEd Tanous roleId, enabled); 190597e90da3SNinad Palsule } 190697e90da3SNinad Palsule 19071ef4c342SEd Tanous inline void handleAccountCollectionPost( 19081ef4c342SEd Tanous App& app, const crow::Request& req, 19091ef4c342SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 19101ef4c342SEd Tanous { 19113ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 191245ca1b86SEd Tanous { 191345ca1b86SEd Tanous return; 191445ca1b86SEd Tanous } 19159712f8acSEd Tanous std::string username; 19169712f8acSEd Tanous std::string password; 1917e01d0c36SEd Tanous std::optional<std::string> roleIdJson; 1918e01d0c36SEd Tanous std::optional<bool> enabledJson; 19199ba73934SNinad Palsule std::optional<std::vector<std::string>> accountTypes; 1920afc474aeSMyung Bae if (!json_util::readJsonPatch( // 1921afc474aeSMyung Bae req, asyncResp->res, // 1922afc474aeSMyung Bae "AccountTypes", accountTypes, // 1923afc474aeSMyung Bae "Enabled", enabledJson, // 1924afc474aeSMyung Bae "Password", password, // 1925afc474aeSMyung Bae "RoleId", roleIdJson, // 1926afc474aeSMyung Bae "UserName", username // 1927afc474aeSMyung Bae )) 192804ae99ecSEd Tanous { 192904ae99ecSEd Tanous return; 193004ae99ecSEd Tanous } 193104ae99ecSEd Tanous 1932e01d0c36SEd Tanous std::string roleId = roleIdJson.value_or("User"); 1933e01d0c36SEd Tanous std::string priv = getPrivilegeFromRoleId(roleId); 193484e12cb7SAppaRao Puli if (priv.empty()) 193504ae99ecSEd Tanous { 1936e01d0c36SEd Tanous messages::propertyValueNotInList(asyncResp->res, roleId, "RoleId"); 193704ae99ecSEd Tanous return; 193804ae99ecSEd Tanous } 19399712f8acSEd Tanous roleId = priv; 194004ae99ecSEd Tanous 1941e01d0c36SEd Tanous bool enabled = enabledJson.value_or(true); 1942e01d0c36SEd Tanous 1943599c71d8SAyushi Smriti // Reading AllGroups property 1944deae6a78SEd Tanous dbus::utility::getProperty<std::vector<std::string>>( 1945deae6a78SEd Tanous "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user", 1946deae6a78SEd Tanous "xyz.openbmc_project.User.Manager", "AllGroups", 19479ba73934SNinad Palsule [asyncResp, username, password{std::move(password)}, roleId, enabled, 19489ba73934SNinad Palsule accountTypes](const boost::system::error_code& ec, 19491e1e598dSJonathan Doman const std::vector<std::string>& allGroupsList) { 1950599c71d8SAyushi Smriti if (ec) 1951599c71d8SAyushi Smriti { 1952a0735a4eSGunnar Mills BMCWEB_LOG_ERROR("D-Bus response error {}", ec); 1953599c71d8SAyushi Smriti messages::internalError(asyncResp->res); 1954599c71d8SAyushi Smriti return; 1955599c71d8SAyushi Smriti } 1956599c71d8SAyushi Smriti 19571e1e598dSJonathan Doman if (allGroupsList.empty()) 1958599c71d8SAyushi Smriti { 1959599c71d8SAyushi Smriti messages::internalError(asyncResp->res); 1960599c71d8SAyushi Smriti return; 1961599c71d8SAyushi Smriti } 1962599c71d8SAyushi Smriti 1963bd79bce8SPatrick Williams processAfterGetAllGroups(asyncResp, username, password, roleId, 1964bd79bce8SPatrick Williams enabled, accountTypes, allGroupsList); 19651e1e598dSJonathan Doman }); 19661ef4c342SEd Tanous } 1967b9b2e0b2SEd Tanous 19681ef4c342SEd Tanous inline void 19694c7d4d33SEd Tanous handleAccountHead(App& app, const crow::Request& req, 19706c51eab1SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 19714c7d4d33SEd Tanous const std::string& /*accountName*/) 19721ef4c342SEd Tanous { 19733ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 197445ca1b86SEd Tanous { 197545ca1b86SEd Tanous return; 197645ca1b86SEd Tanous } 19774c7d4d33SEd Tanous asyncResp->res.addHeader( 19784c7d4d33SEd Tanous boost::beast::http::field::link, 19794c7d4d33SEd Tanous "</redfish/v1/JsonSchemas/ManagerAccount/ManagerAccount.json>; rel=describedby"); 19804c7d4d33SEd Tanous } 1981afd369c6SJiaqing Zhao 19824c7d4d33SEd Tanous inline void 19834c7d4d33SEd Tanous handleAccountGet(App& app, const crow::Request& req, 19844c7d4d33SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 19854c7d4d33SEd Tanous const std::string& accountName) 19864c7d4d33SEd Tanous { 1987afd369c6SJiaqing Zhao if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 1988afd369c6SJiaqing Zhao { 1989afd369c6SJiaqing Zhao return; 1990afd369c6SJiaqing Zhao } 1991afd369c6SJiaqing Zhao asyncResp->res.addHeader( 1992afd369c6SJiaqing Zhao boost::beast::http::field::link, 1993afd369c6SJiaqing Zhao "</redfish/v1/JsonSchemas/ManagerAccount/ManagerAccount.json>; rel=describedby"); 1994afd369c6SJiaqing Zhao 199525b54dbaSEd Tanous if constexpr (BMCWEB_INSECURE_DISABLE_AUTH) 199625b54dbaSEd Tanous { 1997031514fbSJunLin Chen // If authentication is disabled, there are no user accounts 199825b54dbaSEd Tanous messages::resourceNotFound(asyncResp->res, "ManagerAccount", 199925b54dbaSEd Tanous accountName); 2000031514fbSJunLin Chen return; 200125b54dbaSEd Tanous } 2002afd369c6SJiaqing Zhao 2003031514fbSJunLin Chen if (req.session == nullptr) 2004031514fbSJunLin Chen { 2005031514fbSJunLin Chen messages::internalError(asyncResp->res); 2006031514fbSJunLin Chen return; 2007031514fbSJunLin Chen } 20086c51eab1SEd Tanous if (req.session->username != accountName) 2009b9b2e0b2SEd Tanous { 20106c51eab1SEd Tanous // At this point we've determined that the user is trying to 20111ef4c342SEd Tanous // modify a user that isn't them. We need to verify that they 20121ef4c342SEd Tanous // have permissions to modify other users, so re-run the auth 20131ef4c342SEd Tanous // check with the same permissions, minus ConfigureSelf. 20146c51eab1SEd Tanous Privileges effectiveUserPrivileges = 20153e72c202SNinad Palsule redfish::getUserPrivileges(*req.session); 20161ef4c342SEd Tanous Privileges requiredPermissionsToChangeNonSelf = {"ConfigureUsers", 20171ef4c342SEd Tanous "ConfigureManager"}; 20186c51eab1SEd Tanous if (!effectiveUserPrivileges.isSupersetOf( 20196c51eab1SEd Tanous requiredPermissionsToChangeNonSelf)) 2020900f9497SJoseph Reynolds { 202162598e31SEd Tanous BMCWEB_LOG_DEBUG("GET Account denied access"); 2022900f9497SJoseph Reynolds messages::insufficientPrivilege(asyncResp->res); 2023900f9497SJoseph Reynolds return; 2024900f9497SJoseph Reynolds } 2025900f9497SJoseph Reynolds } 2026900f9497SJoseph Reynolds 20275eb468daSGeorge Liu sdbusplus::message::object_path path("/xyz/openbmc_project/user"); 20285eb468daSGeorge Liu dbus::utility::getManagedObjects( 20295eb468daSGeorge Liu "xyz.openbmc_project.User.Manager", path, 20301ef4c342SEd Tanous [asyncResp, 20315e7e2dc5SEd Tanous accountName](const boost::system::error_code& ec, 2032711ac7a9SEd Tanous const dbus::utility::ManagedObjectType& users) { 2033b9b2e0b2SEd Tanous if (ec) 2034b9b2e0b2SEd Tanous { 2035f12894f8SJason M. Bills messages::internalError(asyncResp->res); 2036b9b2e0b2SEd Tanous return; 2037b9b2e0b2SEd Tanous } 20383544d2a7SEd Tanous const auto userIt = std::ranges::find_if( 203980f79a40SMichael Shen users, 204080f79a40SMichael Shen [accountName]( 2041b477fd44SP Dheeraj Srujan Kumar const std::pair<sdbusplus::message::object_path, 204280f79a40SMichael Shen dbus::utility::DBusInterfacesMap>& user) { 204355f79e6fSEd Tanous return accountName == user.first.filename(); 2044b477fd44SP Dheeraj Srujan Kumar }); 2045b9b2e0b2SEd Tanous 204684e12cb7SAppaRao Puli if (userIt == users.end()) 2047b9b2e0b2SEd Tanous { 2048002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "ManagerAccount", 2049002d39b4SEd Tanous accountName); 205084e12cb7SAppaRao Puli return; 205184e12cb7SAppaRao Puli } 20524e68c45bSAyushi Smriti 20531476687dSEd Tanous asyncResp->res.jsonValue["@odata.type"] = 205458345856SAbhishek Patel "#ManagerAccount.v1_7_0.ManagerAccount"; 20551476687dSEd Tanous asyncResp->res.jsonValue["Name"] = "User Account"; 20561476687dSEd Tanous asyncResp->res.jsonValue["Description"] = "User Account"; 20571476687dSEd Tanous asyncResp->res.jsonValue["Password"] = nullptr; 205858345856SAbhishek Patel asyncResp->res.jsonValue["StrictAccountTypes"] = true; 20594e68c45bSAyushi Smriti 206084e12cb7SAppaRao Puli for (const auto& interface : userIt->second) 206165b0dc32SEd Tanous { 2062002d39b4SEd Tanous if (interface.first == "xyz.openbmc_project.User.Attributes") 206365b0dc32SEd Tanous { 2064b437a535SAsmitha Karunanithi const bool* userEnabled = nullptr; 2065b437a535SAsmitha Karunanithi const bool* userLocked = nullptr; 2066b437a535SAsmitha Karunanithi const std::string* userPrivPtr = nullptr; 2067b437a535SAsmitha Karunanithi const bool* userPasswordExpired = nullptr; 2068b437a535SAsmitha Karunanithi const std::vector<std::string>* userGroups = nullptr; 2069b437a535SAsmitha Karunanithi 2070b437a535SAsmitha Karunanithi const bool success = sdbusplus::unpackPropertiesNoThrow( 2071b437a535SAsmitha Karunanithi dbus_utils::UnpackErrorPrinter(), interface.second, 2072b437a535SAsmitha Karunanithi "UserEnabled", userEnabled, 2073b437a535SAsmitha Karunanithi "UserLockedForFailedAttempt", userLocked, 2074b437a535SAsmitha Karunanithi "UserPrivilege", userPrivPtr, "UserPasswordExpired", 2075b437a535SAsmitha Karunanithi userPasswordExpired, "UserGroups", userGroups); 2076b437a535SAsmitha Karunanithi if (!success) 207765b0dc32SEd Tanous { 2078b437a535SAsmitha Karunanithi messages::internalError(asyncResp->res); 2079b437a535SAsmitha Karunanithi return; 2080b437a535SAsmitha Karunanithi } 208165b0dc32SEd Tanous if (userEnabled == nullptr) 208265b0dc32SEd Tanous { 208362598e31SEd Tanous BMCWEB_LOG_ERROR("UserEnabled wasn't a bool"); 208484e12cb7SAppaRao Puli messages::internalError(asyncResp->res); 208584e12cb7SAppaRao Puli return; 208665b0dc32SEd Tanous } 2087002d39b4SEd Tanous asyncResp->res.jsonValue["Enabled"] = *userEnabled; 2088b437a535SAsmitha Karunanithi 208965b0dc32SEd Tanous if (userLocked == nullptr) 209065b0dc32SEd Tanous { 209162598e31SEd Tanous BMCWEB_LOG_ERROR("UserLockedForF" 209284e12cb7SAppaRao Puli "ailedAttempt " 209362598e31SEd Tanous "wasn't a bool"); 209484e12cb7SAppaRao Puli messages::internalError(asyncResp->res); 209584e12cb7SAppaRao Puli return; 209665b0dc32SEd Tanous } 2097002d39b4SEd Tanous asyncResp->res.jsonValue["Locked"] = *userLocked; 209820fa6a2cSEd Tanous nlohmann::json::array_t allowed; 209920fa6a2cSEd Tanous // can only unlock accounts 210020fa6a2cSEd Tanous allowed.emplace_back("false"); 2101b437a535SAsmitha Karunanithi asyncResp->res.jsonValue["Locked@Redfish.AllowableValues"] = 210220fa6a2cSEd Tanous std::move(allowed); 2103b437a535SAsmitha Karunanithi 210454fc587aSNagaraju Goruganti if (userPrivPtr == nullptr) 210584e12cb7SAppaRao Puli { 210662598e31SEd Tanous BMCWEB_LOG_ERROR("UserPrivilege wasn't a " 210762598e31SEd Tanous "string"); 210884e12cb7SAppaRao Puli messages::internalError(asyncResp->res); 210984e12cb7SAppaRao Puli return; 211084e12cb7SAppaRao Puli } 2111b437a535SAsmitha Karunanithi std::string role = getRoleIdFromPrivilege(*userPrivPtr); 211254fc587aSNagaraju Goruganti if (role.empty()) 211384e12cb7SAppaRao Puli { 211462598e31SEd Tanous BMCWEB_LOG_ERROR("Invalid user role"); 211584e12cb7SAppaRao Puli messages::internalError(asyncResp->res); 211684e12cb7SAppaRao Puli return; 211784e12cb7SAppaRao Puli } 211854fc587aSNagaraju Goruganti asyncResp->res.jsonValue["RoleId"] = role; 211984e12cb7SAppaRao Puli 21201476687dSEd Tanous nlohmann::json& roleEntry = 2121002d39b4SEd Tanous asyncResp->res.jsonValue["Links"]["Role"]; 21223b32780dSEd Tanous roleEntry["@odata.id"] = boost::urls::format( 21233b32780dSEd Tanous "/redfish/v1/AccountService/Roles/{}", role); 2124b437a535SAsmitha Karunanithi 21253bf4e632SJoseph Reynolds if (userPasswordExpired == nullptr) 21263bf4e632SJoseph Reynolds { 2127b437a535SAsmitha Karunanithi BMCWEB_LOG_ERROR("UserPasswordExpired wasn't a bool"); 21283bf4e632SJoseph Reynolds messages::internalError(asyncResp->res); 21293bf4e632SJoseph Reynolds return; 21303bf4e632SJoseph Reynolds } 2131002d39b4SEd Tanous asyncResp->res.jsonValue["PasswordChangeRequired"] = 21323bf4e632SJoseph Reynolds *userPasswordExpired; 2133b437a535SAsmitha Karunanithi 2134c7229815SAbhishek Patel if (userGroups == nullptr) 2135c7229815SAbhishek Patel { 2136b437a535SAsmitha Karunanithi BMCWEB_LOG_ERROR("userGroups wasn't a string vector"); 2137c7229815SAbhishek Patel messages::internalError(asyncResp->res); 2138c7229815SAbhishek Patel return; 2139c7229815SAbhishek Patel } 2140b437a535SAsmitha Karunanithi if (!translateUserGroup(*userGroups, asyncResp->res)) 2141c7229815SAbhishek Patel { 214262598e31SEd Tanous BMCWEB_LOG_ERROR("userGroups mapping failed"); 2143c7229815SAbhishek Patel messages::internalError(asyncResp->res); 2144c7229815SAbhishek Patel return; 2145c7229815SAbhishek Patel } 2146c7229815SAbhishek Patel } 214765b0dc32SEd Tanous } 214865b0dc32SEd Tanous 21493b32780dSEd Tanous asyncResp->res.jsonValue["@odata.id"] = boost::urls::format( 21503b32780dSEd Tanous "/redfish/v1/AccountService/Accounts/{}", accountName); 2151b9b2e0b2SEd Tanous asyncResp->res.jsonValue["Id"] = accountName; 2152b9b2e0b2SEd Tanous asyncResp->res.jsonValue["UserName"] = accountName; 21535eb468daSGeorge Liu }); 21541ef4c342SEd Tanous } 2155a840879dSEd Tanous 21561ef4c342SEd Tanous inline void 215720fc307fSGunnar Mills handleAccountDelete(App& app, const crow::Request& req, 21586c51eab1SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 21591ef4c342SEd Tanous const std::string& username) 21601ef4c342SEd Tanous { 21613ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 216245ca1b86SEd Tanous { 216345ca1b86SEd Tanous return; 216445ca1b86SEd Tanous } 21651ef4c342SEd Tanous 216625b54dbaSEd Tanous if constexpr (BMCWEB_INSECURE_DISABLE_AUTH) 216725b54dbaSEd Tanous { 2168031514fbSJunLin Chen // If authentication is disabled, there are no user accounts 2169d8a5d5d8SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "ManagerAccount", username); 2170031514fbSJunLin Chen return; 217125b54dbaSEd Tanous } 21721ef4c342SEd Tanous sdbusplus::message::object_path tempObjPath(rootUserDbusPath); 21731ef4c342SEd Tanous tempObjPath /= username; 21741ef4c342SEd Tanous const std::string userPath(tempObjPath); 21751ef4c342SEd Tanous 21761ef4c342SEd Tanous crow::connections::systemBus->async_method_call( 21775e7e2dc5SEd Tanous [asyncResp, username](const boost::system::error_code& ec) { 21781ef4c342SEd Tanous if (ec) 21791ef4c342SEd Tanous { 2180d8a5d5d8SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "ManagerAccount", 21811ef4c342SEd Tanous username); 21821ef4c342SEd Tanous return; 21831ef4c342SEd Tanous } 21841ef4c342SEd Tanous 21851ef4c342SEd Tanous messages::accountRemoved(asyncResp->res); 21861ef4c342SEd Tanous }, 21871ef4c342SEd Tanous "xyz.openbmc_project.User.Manager", userPath, 21881ef4c342SEd Tanous "xyz.openbmc_project.Object.Delete", "Delete"); 21891ef4c342SEd Tanous } 21901ef4c342SEd Tanous 21911ef4c342SEd Tanous inline void 21921ef4c342SEd Tanous handleAccountPatch(App& app, const crow::Request& req, 21931ef4c342SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 21941ef4c342SEd Tanous const std::string& username) 21951ef4c342SEd Tanous { 21961ef4c342SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 21971ef4c342SEd Tanous { 21981ef4c342SEd Tanous return; 21991ef4c342SEd Tanous } 220025b54dbaSEd Tanous if constexpr (BMCWEB_INSECURE_DISABLE_AUTH) 220125b54dbaSEd Tanous { 22021ef4c342SEd Tanous // If authentication is disabled, there are no user accounts 2203d8a5d5d8SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "ManagerAccount", username); 22041ef4c342SEd Tanous return; 220525b54dbaSEd Tanous } 2206a24526dcSEd Tanous std::optional<std::string> newUserName; 2207a24526dcSEd Tanous std::optional<std::string> password; 2208a24526dcSEd Tanous std::optional<bool> enabled; 2209a24526dcSEd Tanous std::optional<std::string> roleId; 221024c8542dSRatan Gupta std::optional<bool> locked; 221158345856SAbhishek Patel std::optional<std::vector<std::string>> accountTypes; 221258345856SAbhishek Patel 2213031514fbSJunLin Chen if (req.session == nullptr) 2214031514fbSJunLin Chen { 2215031514fbSJunLin Chen messages::internalError(asyncResp->res); 2216031514fbSJunLin Chen return; 2217031514fbSJunLin Chen } 2218031514fbSJunLin Chen 22192b9c1dfeSEd Tanous bool userSelf = (username == req.session->username); 22202b9c1dfeSEd Tanous 2221e9cc5172SEd Tanous Privileges effectiveUserPrivileges = 22223e72c202SNinad Palsule redfish::getUserPrivileges(*req.session); 2223e9cc5172SEd Tanous Privileges configureUsers = {"ConfigureUsers"}; 2224e9cc5172SEd Tanous bool userHasConfigureUsers = 2225e9cc5172SEd Tanous effectiveUserPrivileges.isSupersetOf(configureUsers); 2226e9cc5172SEd Tanous if (userHasConfigureUsers) 2227e9cc5172SEd Tanous { 2228e9cc5172SEd Tanous // Users with ConfigureUsers can modify for all users 2229afc474aeSMyung Bae if (!json_util::readJsonPatch( // 2230afc474aeSMyung Bae req, asyncResp->res, // 2231afc474aeSMyung Bae "AccountTypes", accountTypes, // 2232afc474aeSMyung Bae "Enabled", enabled, // 2233afc474aeSMyung Bae "Locked", locked, // 2234afc474aeSMyung Bae "Password", password, // 2235afc474aeSMyung Bae "RoleId", roleId, // 2236afc474aeSMyung Bae "UserName", newUserName // 2237afc474aeSMyung Bae )) 2238a840879dSEd Tanous { 2239a840879dSEd Tanous return; 2240a840879dSEd Tanous } 2241e9cc5172SEd Tanous } 2242e9cc5172SEd Tanous else 2243900f9497SJoseph Reynolds { 2244e9cc5172SEd Tanous // ConfigureSelf accounts can only modify their own account 224558345856SAbhishek Patel if (!userSelf) 2246900f9497SJoseph Reynolds { 2247900f9497SJoseph Reynolds messages::insufficientPrivilege(asyncResp->res); 2248900f9497SJoseph Reynolds return; 2249900f9497SJoseph Reynolds } 2250031514fbSJunLin Chen 2251e9cc5172SEd Tanous // ConfigureSelf accounts can only modify their password 22521ef4c342SEd Tanous if (!json_util::readJsonPatch(req, asyncResp->res, "Password", 22531ef4c342SEd Tanous password)) 2254e9cc5172SEd Tanous { 2255e9cc5172SEd Tanous return; 2256e9cc5172SEd Tanous } 2257900f9497SJoseph Reynolds } 2258900f9497SJoseph Reynolds 225966b5ca76Sjayaprakash Mutyala // if user name is not provided in the patch method or if it 22606c51eab1SEd Tanous // matches the user name in the URI, then we are treating it as 22616c51eab1SEd Tanous // updating user properties other then username. If username 22626c51eab1SEd Tanous // provided doesn't match the URI, then we are treating this as 22636c51eab1SEd Tanous // user rename request. 226466b5ca76Sjayaprakash Mutyala if (!newUserName || (newUserName.value() == username)) 2265a840879dSEd Tanous { 22661ef4c342SEd Tanous updateUserProperties(asyncResp, username, password, enabled, roleId, 2267e518ef32SRavi Teja locked, accountTypes, userSelf, req.session); 226884e12cb7SAppaRao Puli return; 226984e12cb7SAppaRao Puli } 227084e12cb7SAppaRao Puli crow::connections::systemBus->async_method_call( 22716c51eab1SEd Tanous [asyncResp, username, password(std::move(password)), 22721ef4c342SEd Tanous roleId(std::move(roleId)), enabled, newUser{std::string(*newUserName)}, 2273e518ef32SRavi Teja locked, userSelf, req, accountTypes(std::move(accountTypes))]( 2274e81de512SEd Tanous const boost::system::error_code& ec, sdbusplus::message_t& m) { 227584e12cb7SAppaRao Puli if (ec) 227684e12cb7SAppaRao Puli { 2277002d39b4SEd Tanous userErrorMessageHandler(m.get_error(), asyncResp, newUser, 2278002d39b4SEd Tanous username); 2279a840879dSEd Tanous return; 2280a840879dSEd Tanous } 2281a840879dSEd Tanous 2282002d39b4SEd Tanous updateUserProperties(asyncResp, newUser, password, enabled, roleId, 2283e518ef32SRavi Teja locked, accountTypes, userSelf, req.session); 228484e12cb7SAppaRao Puli }, 22851ef4c342SEd Tanous "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user", 228684e12cb7SAppaRao Puli "xyz.openbmc_project.User.Manager", "RenameUser", username, 228784e12cb7SAppaRao Puli *newUserName); 22881ef4c342SEd Tanous } 22891ef4c342SEd Tanous 22901ef4c342SEd Tanous inline void requestAccountServiceRoutes(App& app) 22911ef4c342SEd Tanous { 22921ef4c342SEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/AccountService/") 22934c7d4d33SEd Tanous .privileges(redfish::privileges::headAccountService) 22944c7d4d33SEd Tanous .methods(boost::beast::http::verb::head)( 22954c7d4d33SEd Tanous std::bind_front(handleAccountServiceHead, std::ref(app))); 22964c7d4d33SEd Tanous 22974c7d4d33SEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/AccountService/") 22981ef4c342SEd Tanous .privileges(redfish::privileges::getAccountService) 22991ef4c342SEd Tanous .methods(boost::beast::http::verb::get)( 23001ef4c342SEd Tanous std::bind_front(handleAccountServiceGet, std::ref(app))); 23011ef4c342SEd Tanous 23021ef4c342SEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/AccountService/") 23031ef4c342SEd Tanous .privileges(redfish::privileges::patchAccountService) 23041ef4c342SEd Tanous .methods(boost::beast::http::verb::patch)( 23051ef4c342SEd Tanous std::bind_front(handleAccountServicePatch, std::ref(app))); 23061ef4c342SEd Tanous 23071aa375b8SEd Tanous BMCWEB_ROUTE( 23081aa375b8SEd Tanous app, 2309e9f12014SEd Tanous "/redfish/v1/AccountService/MultiFactorAuth/ClientCertificate/Certificates/") 23101aa375b8SEd Tanous .privileges(redfish::privileges::headCertificateCollection) 23111aa375b8SEd Tanous .methods(boost::beast::http::verb::head)(std::bind_front( 23121aa375b8SEd Tanous handleAccountServiceClientCertificatesHead, std::ref(app))); 23131aa375b8SEd Tanous 23141aa375b8SEd Tanous BMCWEB_ROUTE( 23151aa375b8SEd Tanous app, 2316e9f12014SEd Tanous "/redfish/v1/AccountService/MultiFactorAuth/ClientCertificate/Certificates/") 23171aa375b8SEd Tanous .privileges(redfish::privileges::getCertificateCollection) 23181aa375b8SEd Tanous .methods(boost::beast::http::verb::get)(std::bind_front( 23191aa375b8SEd Tanous handleAccountServiceClientCertificatesGet, std::ref(app))); 23201aa375b8SEd Tanous 23211aa375b8SEd Tanous BMCWEB_ROUTE( 23221aa375b8SEd Tanous app, 2323e9f12014SEd Tanous "/redfish/v1/AccountService/MultiFactorAuth/ClientCertificate/Certificates/<str>/") 23241aa375b8SEd Tanous .privileges(redfish::privileges::headCertificate) 23251aa375b8SEd Tanous .methods(boost::beast::http::verb::head)(std::bind_front( 23261aa375b8SEd Tanous handleAccountServiceClientCertificatesInstanceHead, std::ref(app))); 23271aa375b8SEd Tanous 23281aa375b8SEd Tanous BMCWEB_ROUTE( 23291aa375b8SEd Tanous app, 23301aa375b8SEd Tanous "/redfish/v1/AccountService/MultiFactorAuth/ClientCertificate/Certificates/<str>/") 23311aa375b8SEd Tanous .privileges(redfish::privileges::getCertificate) 23321aa375b8SEd Tanous .methods(boost::beast::http::verb::get)(std::bind_front( 23331aa375b8SEd Tanous handleAccountServiceClientCertificatesInstanceGet, std::ref(app))); 23341aa375b8SEd Tanous 23351ef4c342SEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/") 23364c7d4d33SEd Tanous .privileges(redfish::privileges::headManagerAccountCollection) 23374c7d4d33SEd Tanous .methods(boost::beast::http::verb::head)( 23384c7d4d33SEd Tanous std::bind_front(handleAccountCollectionHead, std::ref(app))); 23394c7d4d33SEd Tanous 23404c7d4d33SEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/") 23411ef4c342SEd Tanous .privileges(redfish::privileges::getManagerAccountCollection) 23421ef4c342SEd Tanous .methods(boost::beast::http::verb::get)( 23431ef4c342SEd Tanous std::bind_front(handleAccountCollectionGet, std::ref(app))); 23441ef4c342SEd Tanous 23451ef4c342SEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/") 23461ef4c342SEd Tanous .privileges(redfish::privileges::postManagerAccountCollection) 23471ef4c342SEd Tanous .methods(boost::beast::http::verb::post)( 23481ef4c342SEd Tanous std::bind_front(handleAccountCollectionPost, std::ref(app))); 23491ef4c342SEd Tanous 23501ef4c342SEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/<str>/") 23514c7d4d33SEd Tanous .privileges(redfish::privileges::headManagerAccount) 23524c7d4d33SEd Tanous .methods(boost::beast::http::verb::head)( 23534c7d4d33SEd Tanous std::bind_front(handleAccountHead, std::ref(app))); 23544c7d4d33SEd Tanous 23554c7d4d33SEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/<str>/") 23561ef4c342SEd Tanous .privileges(redfish::privileges::getManagerAccount) 23571ef4c342SEd Tanous .methods(boost::beast::http::verb::get)( 23581ef4c342SEd Tanous std::bind_front(handleAccountGet, std::ref(app))); 23591ef4c342SEd Tanous 23601ef4c342SEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/<str>/") 23611ef4c342SEd Tanous // TODO this privilege should be using the generated endpoints, but 23621ef4c342SEd Tanous // because of the special handling of ConfigureSelf, it's not able to 23631ef4c342SEd Tanous // yet 23641ef4c342SEd Tanous .privileges({{"ConfigureUsers"}, {"ConfigureSelf"}}) 23651ef4c342SEd Tanous .methods(boost::beast::http::verb::patch)( 23661ef4c342SEd Tanous std::bind_front(handleAccountPatch, std::ref(app))); 236784e12cb7SAppaRao Puli 23686c51eab1SEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/<str>/") 2369ed398213SEd Tanous .privileges(redfish::privileges::deleteManagerAccount) 23706c51eab1SEd Tanous .methods(boost::beast::http::verb::delete_)( 237120fc307fSGunnar Mills std::bind_front(handleAccountDelete, std::ref(app))); 237206e086d9SEd Tanous } 237388d16c9aSLewanczyk, Dawid 237488d16c9aSLewanczyk, Dawid } // namespace redfish 2375