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 420c1019828SEd Tanous if (!json_util::readJsonObject(*obj, asyncResp->res, "RemoteGroup", 421c1019828SEd Tanous remoteGroup, "LocalRole", localRole)) 42206785244SRatan Gupta { 42306785244SRatan Gupta continue; 42406785244SRatan Gupta } 42506785244SRatan Gupta 42606785244SRatan Gupta // Update existing RoleMapping Object 42706785244SRatan Gupta if (index < roleMapObjData.size()) 42806785244SRatan Gupta { 42962598e31SEd Tanous BMCWEB_LOG_DEBUG("Update Role Map Object"); 43006785244SRatan Gupta // If "RemoteGroup" info is provided 43106785244SRatan Gupta if (remoteGroup) 43206785244SRatan Gupta { 433d02aad39SEd Tanous setDbusProperty( 434e93abac6SGinu George asyncResp, 435d02aad39SEd Tanous std::format("RemoteRoleMapping/{}/RemoteGroup", index), 436e93abac6SGinu George ldapDbusService, roleMapObjData[index].first, 437e93abac6SGinu George "xyz.openbmc_project.User.PrivilegeMapperEntry", 438e93abac6SGinu George "GroupName", *remoteGroup); 43906785244SRatan Gupta } 44006785244SRatan Gupta 44106785244SRatan Gupta // If "LocalRole" info is provided 44206785244SRatan Gupta if (localRole) 44306785244SRatan Gupta { 4446d0b80beSRavi Teja std::string priv = getPrivilegeFromRoleId(*localRole); 4456d0b80beSRavi Teja if (priv.empty()) 4466d0b80beSRavi Teja { 4476d0b80beSRavi Teja messages::propertyValueNotInList( 4486d0b80beSRavi Teja asyncResp->res, *localRole, 4496d0b80beSRavi Teja std::format("RemoteRoleMapping/{}/LocalRole", 4506d0b80beSRavi Teja index)); 4516d0b80beSRavi Teja return; 4526d0b80beSRavi Teja } 453d02aad39SEd Tanous setDbusProperty( 454e93abac6SGinu George asyncResp, 455d02aad39SEd Tanous std::format("RemoteRoleMapping/{}/LocalRole", index), 456e93abac6SGinu George ldapDbusService, roleMapObjData[index].first, 457e93abac6SGinu George "xyz.openbmc_project.User.PrivilegeMapperEntry", 4586d0b80beSRavi Teja "Privilege", priv); 45906785244SRatan Gupta } 46006785244SRatan Gupta } 46106785244SRatan Gupta // Create a new RoleMapping Object. 46206785244SRatan Gupta else 46306785244SRatan Gupta { 46462598e31SEd Tanous BMCWEB_LOG_DEBUG( 46562598e31SEd Tanous "setRoleMappingProperties: Creating new Object"); 466bd79bce8SPatrick Williams std::string pathString = 467bd79bce8SPatrick Williams "RemoteRoleMapping/" + std::to_string(index); 46806785244SRatan Gupta 46906785244SRatan Gupta if (!localRole) 47006785244SRatan Gupta { 47106785244SRatan Gupta messages::propertyMissing(asyncResp->res, 47206785244SRatan Gupta pathString + "/LocalRole"); 47306785244SRatan Gupta continue; 47406785244SRatan Gupta } 47506785244SRatan Gupta if (!remoteGroup) 47606785244SRatan Gupta { 47706785244SRatan Gupta messages::propertyMissing(asyncResp->res, 47806785244SRatan Gupta pathString + "/RemoteGroup"); 47906785244SRatan Gupta continue; 48006785244SRatan Gupta } 48106785244SRatan Gupta 48206785244SRatan Gupta std::string dbusObjectPath; 48306785244SRatan Gupta if (serverType == "ActiveDirectory") 48406785244SRatan Gupta { 4852c70f800SEd Tanous dbusObjectPath = adConfigObject; 48606785244SRatan Gupta } 48706785244SRatan Gupta else if (serverType == "LDAP") 48806785244SRatan Gupta { 48923a21a1cSEd Tanous dbusObjectPath = ldapConfigObjectName; 49006785244SRatan Gupta } 49106785244SRatan Gupta 49262598e31SEd Tanous BMCWEB_LOG_DEBUG("Remote Group={},LocalRole={}", *remoteGroup, 49362598e31SEd Tanous *localRole); 49406785244SRatan Gupta 49506785244SRatan Gupta crow::connections::systemBus->async_method_call( 496271584abSEd Tanous [asyncResp, serverType, localRole, 4975e7e2dc5SEd Tanous remoteGroup](const boost::system::error_code& ec) { 49806785244SRatan Gupta if (ec) 49906785244SRatan Gupta { 50062598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error: {}", ec); 50106785244SRatan Gupta messages::internalError(asyncResp->res); 50206785244SRatan Gupta return; 50306785244SRatan Gupta } 50406785244SRatan Gupta nlohmann::json& remoteRoleJson = 50506785244SRatan Gupta asyncResp->res 50606785244SRatan Gupta .jsonValue[serverType]["RemoteRoleMapping"]; 5071476687dSEd Tanous nlohmann::json::object_t roleMapEntry; 5081476687dSEd Tanous roleMapEntry["LocalRole"] = *localRole; 5091476687dSEd Tanous roleMapEntry["RemoteGroup"] = *remoteGroup; 510b2ba3072SPatrick Williams remoteRoleJson.emplace_back(std::move(roleMapEntry)); 51106785244SRatan Gupta }, 51206785244SRatan Gupta ldapDbusService, dbusObjectPath, ldapPrivMapperInterface, 5133174e4dfSEd Tanous "Create", *remoteGroup, 51406785244SRatan Gupta getPrivilegeFromRoleId(std::move(*localRole))); 51506785244SRatan Gupta } 51606785244SRatan Gupta } 51706785244SRatan Gupta } 51806785244SRatan Gupta } 51906785244SRatan Gupta 52006785244SRatan Gupta /** 5216973a582SRatan Gupta * Function that retrieves all properties for LDAP config object 5226973a582SRatan Gupta * into JSON 5236973a582SRatan Gupta */ 5246973a582SRatan Gupta template <typename CallbackFunc> 525bd79bce8SPatrick Williams inline void 526bd79bce8SPatrick Williams getLDAPConfigData(const std::string& ldapType, CallbackFunc&& callback) 5276973a582SRatan Gupta { 5282b73119cSGeorge Liu constexpr std::array<std::string_view, 2> interfaces = { 5292b73119cSGeorge Liu ldapEnableInterface, ldapConfigInterface}; 53054fc587aSNagaraju Goruganti 5312b73119cSGeorge Liu dbus::utility::getDbusObject( 5322b73119cSGeorge Liu ldapConfigObjectName, interfaces, 5338cb2c024SEd Tanous [callback = std::forward<CallbackFunc>(callback), 534c1019828SEd Tanous ldapType](const boost::system::error_code& ec, 535c1019828SEd Tanous const dbus::utility::MapperGetObject& resp) mutable { 53654fc587aSNagaraju Goruganti if (ec || resp.empty()) 53754fc587aSNagaraju Goruganti { 538bf2ddedeSCarson Labrado BMCWEB_LOG_WARNING( 539bd79bce8SPatrick Williams "DBUS response error during getting of service name: {}", 540bd79bce8SPatrick Williams ec); 54123a21a1cSEd Tanous LDAPConfigData empty{}; 54223a21a1cSEd Tanous callback(false, empty, ldapType); 54354fc587aSNagaraju Goruganti return; 54454fc587aSNagaraju Goruganti } 54554fc587aSNagaraju Goruganti std::string service = resp.begin()->first; 5465eb468daSGeorge Liu sdbusplus::message::object_path path(ldapRootObject); 5475eb468daSGeorge Liu dbus::utility::getManagedObjects( 5485eb468daSGeorge Liu service, path, 549bd79bce8SPatrick Williams [callback, ldapType](const boost::system::error_code& ec2, 550bd79bce8SPatrick Williams const dbus::utility::ManagedObjectType& 551bd79bce8SPatrick Williams ldapObjects) mutable { 5526973a582SRatan Gupta LDAPConfigData confData{}; 5538b24275dSEd Tanous if (ec2) 5546973a582SRatan Gupta { 555ab828d7cSRatan Gupta callback(false, confData, ldapType); 556bf2ddedeSCarson Labrado BMCWEB_LOG_WARNING("D-Bus responses error: {}", ec2); 5576973a582SRatan Gupta return; 5586973a582SRatan Gupta } 559ab828d7cSRatan Gupta 560ab828d7cSRatan Gupta std::string ldapDbusType; 56154fc587aSNagaraju Goruganti std::string searchString; 56254fc587aSNagaraju Goruganti 563ab828d7cSRatan Gupta if (ldapType == "LDAP") 564ab828d7cSRatan Gupta { 5650fda0f12SGeorge Liu ldapDbusType = 5660fda0f12SGeorge Liu "xyz.openbmc_project.User.Ldap.Config.Type.OpenLdap"; 56754fc587aSNagaraju Goruganti searchString = "openldap"; 568ab828d7cSRatan Gupta } 569ab828d7cSRatan Gupta else if (ldapType == "ActiveDirectory") 570ab828d7cSRatan Gupta { 57154fc587aSNagaraju Goruganti ldapDbusType = 5720fda0f12SGeorge Liu "xyz.openbmc_project.User.Ldap.Config.Type.ActiveDirectory"; 57354fc587aSNagaraju Goruganti searchString = "active_directory"; 574ab828d7cSRatan Gupta } 575ab828d7cSRatan Gupta else 576ab828d7cSRatan Gupta { 577bd79bce8SPatrick Williams BMCWEB_LOG_ERROR( 578bd79bce8SPatrick Williams "Can't get the DbusType for the given type={}", 57962598e31SEd Tanous ldapType); 580ab828d7cSRatan Gupta callback(false, confData, ldapType); 581ab828d7cSRatan Gupta return; 582ab828d7cSRatan Gupta } 583ab828d7cSRatan Gupta 584ab828d7cSRatan Gupta std::string ldapEnableInterfaceStr = ldapEnableInterface; 585ab828d7cSRatan Gupta std::string ldapConfigInterfaceStr = ldapConfigInterface; 586ab828d7cSRatan Gupta 5876973a582SRatan Gupta for (const auto& object : ldapObjects) 5886973a582SRatan Gupta { 58954fc587aSNagaraju Goruganti // let's find the object whose ldap type is equal to the 59054fc587aSNagaraju Goruganti // given type 591bd79bce8SPatrick Williams if (object.first.str.find(searchString) == 592bd79bce8SPatrick Williams std::string::npos) 5936973a582SRatan Gupta { 594ab828d7cSRatan Gupta continue; 595ab828d7cSRatan Gupta } 596ab828d7cSRatan Gupta 5976973a582SRatan Gupta for (const auto& interface : object.second) 5986973a582SRatan Gupta { 5996973a582SRatan Gupta if (interface.first == ldapEnableInterfaceStr) 6006973a582SRatan Gupta { 6016973a582SRatan Gupta // rest of the properties are string. 6026973a582SRatan Gupta for (const auto& property : interface.second) 6036973a582SRatan Gupta { 6046973a582SRatan Gupta if (property.first == "Enabled") 6056973a582SRatan Gupta { 6066973a582SRatan Gupta const bool* value = 6076973a582SRatan Gupta std::get_if<bool>(&property.second); 6086973a582SRatan Gupta if (value == nullptr) 6096973a582SRatan Gupta { 6106973a582SRatan Gupta continue; 6116973a582SRatan Gupta } 6126973a582SRatan Gupta confData.serviceEnabled = *value; 6136973a582SRatan Gupta break; 6146973a582SRatan Gupta } 6156973a582SRatan Gupta } 6166973a582SRatan Gupta } 6176973a582SRatan Gupta else if (interface.first == ldapConfigInterfaceStr) 6186973a582SRatan Gupta { 6196973a582SRatan Gupta for (const auto& property : interface.second) 6206973a582SRatan Gupta { 621271584abSEd Tanous const std::string* strValue = 622bd79bce8SPatrick Williams std::get_if<std::string>( 623bd79bce8SPatrick Williams &property.second); 624271584abSEd Tanous if (strValue == nullptr) 6256973a582SRatan Gupta { 6266973a582SRatan Gupta continue; 6276973a582SRatan Gupta } 6286973a582SRatan Gupta if (property.first == "LDAPServerURI") 6296973a582SRatan Gupta { 630271584abSEd Tanous confData.uri = *strValue; 6316973a582SRatan Gupta } 6326973a582SRatan Gupta else if (property.first == "LDAPBindDN") 6336973a582SRatan Gupta { 634271584abSEd Tanous confData.bindDN = *strValue; 6356973a582SRatan Gupta } 6366973a582SRatan Gupta else if (property.first == "LDAPBaseDN") 6376973a582SRatan Gupta { 638271584abSEd Tanous confData.baseDN = *strValue; 6396973a582SRatan Gupta } 640bd79bce8SPatrick Williams else if (property.first == 641bd79bce8SPatrick Williams "LDAPSearchScope") 6426973a582SRatan Gupta { 643271584abSEd Tanous confData.searchScope = *strValue; 6446973a582SRatan Gupta } 645bd79bce8SPatrick Williams else if (property.first == 646bd79bce8SPatrick Williams "GroupNameAttribute") 6476973a582SRatan Gupta { 648271584abSEd Tanous confData.groupAttribute = *strValue; 6496973a582SRatan Gupta } 650bd79bce8SPatrick Williams else if (property.first == 651bd79bce8SPatrick Williams "UserNameAttribute") 6526973a582SRatan Gupta { 653271584abSEd Tanous confData.userNameAttribute = *strValue; 6546973a582SRatan Gupta } 65554fc587aSNagaraju Goruganti else if (property.first == "LDAPType") 656ab828d7cSRatan Gupta { 657271584abSEd Tanous confData.serverType = *strValue; 65854fc587aSNagaraju Goruganti } 65954fc587aSNagaraju Goruganti } 66054fc587aSNagaraju Goruganti } 661bd79bce8SPatrick Williams else if ( 662bd79bce8SPatrick Williams interface.first == 6630fda0f12SGeorge Liu "xyz.openbmc_project.User.PrivilegeMapperEntry") 66454fc587aSNagaraju Goruganti { 66554fc587aSNagaraju Goruganti LDAPRoleMapData roleMapData{}; 66654fc587aSNagaraju Goruganti for (const auto& property : interface.second) 66754fc587aSNagaraju Goruganti { 668271584abSEd Tanous const std::string* strValue = 669bd79bce8SPatrick Williams std::get_if<std::string>( 670bd79bce8SPatrick Williams &property.second); 67154fc587aSNagaraju Goruganti 672271584abSEd Tanous if (strValue == nullptr) 67354fc587aSNagaraju Goruganti { 67454fc587aSNagaraju Goruganti continue; 67554fc587aSNagaraju Goruganti } 67654fc587aSNagaraju Goruganti 67754fc587aSNagaraju Goruganti if (property.first == "GroupName") 67854fc587aSNagaraju Goruganti { 679271584abSEd Tanous roleMapData.groupName = *strValue; 68054fc587aSNagaraju Goruganti } 68154fc587aSNagaraju Goruganti else if (property.first == "Privilege") 68254fc587aSNagaraju Goruganti { 683271584abSEd Tanous roleMapData.privilege = *strValue; 68454fc587aSNagaraju Goruganti } 68554fc587aSNagaraju Goruganti } 68654fc587aSNagaraju Goruganti 687bd79bce8SPatrick Williams confData.groupRoleList.emplace_back( 688bd79bce8SPatrick Williams object.first.str, roleMapData); 68954fc587aSNagaraju Goruganti } 69054fc587aSNagaraju Goruganti } 69154fc587aSNagaraju Goruganti } 692ab828d7cSRatan Gupta callback(true, confData, ldapType); 6935eb468daSGeorge Liu }); 6942b73119cSGeorge Liu }); 6956973a582SRatan Gupta } 6966973a582SRatan Gupta 6978a07d286SRatan Gupta /** 6988a07d286SRatan Gupta * @brief updates the LDAP server address and updates the 6998a07d286SRatan Gupta json response with the new value. 7008a07d286SRatan Gupta * @param serviceAddressList address to be updated. 7018a07d286SRatan Gupta * @param asyncResp pointer to the JSON response 7028a07d286SRatan Gupta * @param ldapServerElementName Type of LDAP 7038a07d286SRatan Gupta server(openLDAP/ActiveDirectory) 7048a07d286SRatan Gupta */ 7058a07d286SRatan Gupta 7064f48d5f6SEd Tanous inline void handleServiceAddressPatch( 7078a07d286SRatan Gupta const std::vector<std::string>& serviceAddressList, 7088d1b46d7Szhanghch05 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 7098a07d286SRatan Gupta const std::string& ldapServerElementName, 7108a07d286SRatan Gupta const std::string& ldapConfigObject) 7118a07d286SRatan Gupta { 712e93abac6SGinu George setDbusProperty(asyncResp, ldapServerElementName + "/ServiceAddress", 713e93abac6SGinu George ldapDbusService, ldapConfigObject, ldapConfigInterface, 714e93abac6SGinu George "LDAPServerURI", serviceAddressList.front()); 7158a07d286SRatan Gupta } 7168a07d286SRatan Gupta /** 7178a07d286SRatan Gupta * @brief updates the LDAP Bind DN and updates the 7188a07d286SRatan Gupta json response with the new value. 7198a07d286SRatan Gupta * @param username name of the user which needs to be updated. 7208a07d286SRatan Gupta * @param asyncResp pointer to the JSON response 7218a07d286SRatan Gupta * @param ldapServerElementName Type of LDAP 7228a07d286SRatan Gupta server(openLDAP/ActiveDirectory) 7238a07d286SRatan Gupta */ 7248a07d286SRatan Gupta 7254f48d5f6SEd Tanous inline void 7264f48d5f6SEd Tanous handleUserNamePatch(const std::string& username, 7278d1b46d7Szhanghch05 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 7288a07d286SRatan Gupta const std::string& ldapServerElementName, 7298a07d286SRatan Gupta const std::string& ldapConfigObject) 7308a07d286SRatan Gupta { 731e93abac6SGinu George setDbusProperty(asyncResp, 732d02aad39SEd Tanous ldapServerElementName + "/Authentication/Username", 733e93abac6SGinu George ldapDbusService, ldapConfigObject, ldapConfigInterface, 734e93abac6SGinu George "LDAPBindDN", username); 7358a07d286SRatan Gupta } 7368a07d286SRatan Gupta 7378a07d286SRatan Gupta /** 7388a07d286SRatan Gupta * @brief updates the LDAP password 7398a07d286SRatan Gupta * @param password : ldap password which needs to be updated. 7408a07d286SRatan Gupta * @param asyncResp pointer to the JSON response 7418a07d286SRatan Gupta * @param ldapServerElementName Type of LDAP 7428a07d286SRatan Gupta * server(openLDAP/ActiveDirectory) 7438a07d286SRatan Gupta */ 7448a07d286SRatan Gupta 7454f48d5f6SEd Tanous inline void 7464f48d5f6SEd Tanous handlePasswordPatch(const std::string& password, 7478d1b46d7Szhanghch05 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 7488a07d286SRatan Gupta const std::string& ldapServerElementName, 7498a07d286SRatan Gupta const std::string& ldapConfigObject) 7508a07d286SRatan Gupta { 751e93abac6SGinu George setDbusProperty(asyncResp, 752d02aad39SEd Tanous ldapServerElementName + "/Authentication/Password", 753e93abac6SGinu George ldapDbusService, ldapConfigObject, ldapConfigInterface, 754e93abac6SGinu George "LDAPBindDNPassword", password); 7558a07d286SRatan Gupta } 7568a07d286SRatan Gupta 7578a07d286SRatan Gupta /** 7588a07d286SRatan Gupta * @brief updates the LDAP BaseDN and updates the 7598a07d286SRatan Gupta json response with the new value. 7608a07d286SRatan Gupta * @param baseDNList baseDN list which needs to be updated. 7618a07d286SRatan Gupta * @param asyncResp pointer to the JSON response 7628a07d286SRatan Gupta * @param ldapServerElementName Type of LDAP 7638a07d286SRatan Gupta server(openLDAP/ActiveDirectory) 7648a07d286SRatan Gupta */ 7658a07d286SRatan Gupta 7664f48d5f6SEd Tanous inline void 7674f48d5f6SEd Tanous handleBaseDNPatch(const std::vector<std::string>& baseDNList, 7688d1b46d7Szhanghch05 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 7698a07d286SRatan Gupta const std::string& ldapServerElementName, 7708a07d286SRatan Gupta const std::string& ldapConfigObject) 7718a07d286SRatan Gupta { 772e93abac6SGinu George setDbusProperty(asyncResp, 773d02aad39SEd Tanous ldapServerElementName + 774d02aad39SEd Tanous "/LDAPService/SearchSettings/BaseDistinguishedNames", 775e93abac6SGinu George ldapDbusService, ldapConfigObject, ldapConfigInterface, 776e93abac6SGinu George "LDAPBaseDN", baseDNList.front()); 7778a07d286SRatan Gupta } 7788a07d286SRatan Gupta /** 7798a07d286SRatan Gupta * @brief updates the LDAP user name attribute and updates the 7808a07d286SRatan Gupta json response with the new value. 7818a07d286SRatan Gupta * @param userNameAttribute attribute to be updated. 7828a07d286SRatan Gupta * @param asyncResp pointer to the JSON response 7838a07d286SRatan Gupta * @param ldapServerElementName Type of LDAP 7848a07d286SRatan Gupta server(openLDAP/ActiveDirectory) 7858a07d286SRatan Gupta */ 7868a07d286SRatan Gupta 787bd79bce8SPatrick Williams inline void handleUserNameAttrPatch( 788bd79bce8SPatrick Williams const std::string& userNameAttribute, 7898d1b46d7Szhanghch05 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 7908a07d286SRatan Gupta const std::string& ldapServerElementName, 7918a07d286SRatan Gupta const std::string& ldapConfigObject) 7928a07d286SRatan Gupta { 793bd79bce8SPatrick Williams setDbusProperty( 794bd79bce8SPatrick Williams asyncResp, 795bd79bce8SPatrick Williams ldapServerElementName + "LDAPService/SearchSettings/UsernameAttribute", 796e93abac6SGinu George ldapDbusService, ldapConfigObject, ldapConfigInterface, 797e93abac6SGinu George "UserNameAttribute", userNameAttribute); 7988a07d286SRatan Gupta } 7998a07d286SRatan Gupta /** 8008a07d286SRatan Gupta * @brief updates the LDAP group attribute and updates the 8018a07d286SRatan Gupta json response with the new value. 8028a07d286SRatan Gupta * @param groupsAttribute attribute to be updated. 8038a07d286SRatan Gupta * @param asyncResp pointer to the JSON response 8048a07d286SRatan Gupta * @param ldapServerElementName Type of LDAP 8058a07d286SRatan Gupta server(openLDAP/ActiveDirectory) 8068a07d286SRatan Gupta */ 8078a07d286SRatan Gupta 8084f48d5f6SEd Tanous inline void handleGroupNameAttrPatch( 8098d1b46d7Szhanghch05 const std::string& groupsAttribute, 8108d1b46d7Szhanghch05 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 8118a07d286SRatan Gupta const std::string& ldapServerElementName, 8128a07d286SRatan Gupta const std::string& ldapConfigObject) 8138a07d286SRatan Gupta { 814bd79bce8SPatrick Williams setDbusProperty( 815bd79bce8SPatrick Williams asyncResp, 816bd79bce8SPatrick Williams ldapServerElementName + "/LDAPService/SearchSettings/GroupsAttribute", 817e93abac6SGinu George ldapDbusService, ldapConfigObject, ldapConfigInterface, 818e93abac6SGinu George "GroupNameAttribute", groupsAttribute); 8198a07d286SRatan Gupta } 8208a07d286SRatan Gupta /** 8218a07d286SRatan Gupta * @brief updates the LDAP service enable and updates the 8228a07d286SRatan Gupta json response with the new value. 8238a07d286SRatan Gupta * @param input JSON data. 8248a07d286SRatan Gupta * @param asyncResp pointer to the JSON response 8258a07d286SRatan Gupta * @param ldapServerElementName Type of LDAP 8268a07d286SRatan Gupta server(openLDAP/ActiveDirectory) 8278a07d286SRatan Gupta */ 8288a07d286SRatan Gupta 8294f48d5f6SEd Tanous inline void handleServiceEnablePatch( 8306c51eab1SEd Tanous bool serviceEnabled, const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 8318a07d286SRatan Gupta const std::string& ldapServerElementName, 8328a07d286SRatan Gupta const std::string& ldapConfigObject) 8338a07d286SRatan Gupta { 834e93abac6SGinu George setDbusProperty(asyncResp, ldapServerElementName + "/ServiceEnabled", 835e93abac6SGinu George ldapDbusService, ldapConfigObject, ldapEnableInterface, 836e93abac6SGinu George "Enabled", serviceEnabled); 8378a07d286SRatan Gupta } 8388a07d286SRatan Gupta 839c1019828SEd Tanous struct AuthMethods 84078158631SZbigniew Kurzynski { 84178158631SZbigniew Kurzynski std::optional<bool> basicAuth; 84278158631SZbigniew Kurzynski std::optional<bool> cookie; 84378158631SZbigniew Kurzynski std::optional<bool> sessionToken; 84478158631SZbigniew Kurzynski std::optional<bool> xToken; 845501f1e58SZbigniew Kurzynski std::optional<bool> tls; 846c1019828SEd Tanous }; 84778158631SZbigniew Kurzynski 848c1019828SEd Tanous inline void 849c1019828SEd Tanous handleAuthMethodsPatch(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 850c1019828SEd Tanous const AuthMethods& auth) 85178158631SZbigniew Kurzynski { 852c1019828SEd Tanous persistent_data::AuthConfigMethods& authMethodsConfig = 85352cc112dSEd Tanous persistent_data::SessionStore::getInstance().getAuthMethodsConfig(); 85478158631SZbigniew Kurzynski 855c1019828SEd Tanous if (auth.basicAuth) 85678158631SZbigniew Kurzynski { 85725b54dbaSEd Tanous if constexpr (!BMCWEB_BASIC_AUTH) 85825b54dbaSEd Tanous { 859f16f6263SAlan Kuo messages::actionNotSupported( 8600fda0f12SGeorge Liu asyncResp->res, 8610fda0f12SGeorge Liu "Setting BasicAuth when basic-auth feature is disabled"); 862f16f6263SAlan Kuo return; 86325b54dbaSEd Tanous } 86425b54dbaSEd Tanous 865c1019828SEd Tanous authMethodsConfig.basic = *auth.basicAuth; 86678158631SZbigniew Kurzynski } 86778158631SZbigniew Kurzynski 868c1019828SEd Tanous if (auth.cookie) 86978158631SZbigniew Kurzynski { 87025b54dbaSEd Tanous if constexpr (!BMCWEB_COOKIE_AUTH) 87125b54dbaSEd Tanous { 8720fda0f12SGeorge Liu messages::actionNotSupported( 8730fda0f12SGeorge Liu asyncResp->res, 8740fda0f12SGeorge Liu "Setting Cookie when cookie-auth feature is disabled"); 875f16f6263SAlan Kuo return; 87625b54dbaSEd Tanous } 877c1019828SEd Tanous authMethodsConfig.cookie = *auth.cookie; 87878158631SZbigniew Kurzynski } 87978158631SZbigniew Kurzynski 880c1019828SEd Tanous if (auth.sessionToken) 88178158631SZbigniew Kurzynski { 88225b54dbaSEd Tanous if constexpr (!BMCWEB_SESSION_AUTH) 88325b54dbaSEd Tanous { 884f16f6263SAlan Kuo messages::actionNotSupported( 8850fda0f12SGeorge Liu asyncResp->res, 8860fda0f12SGeorge Liu "Setting SessionToken when session-auth feature is disabled"); 887f16f6263SAlan Kuo return; 88825b54dbaSEd Tanous } 889c1019828SEd Tanous authMethodsConfig.sessionToken = *auth.sessionToken; 89078158631SZbigniew Kurzynski } 89178158631SZbigniew Kurzynski 892c1019828SEd Tanous if (auth.xToken) 89378158631SZbigniew Kurzynski { 89425b54dbaSEd Tanous if constexpr (!BMCWEB_XTOKEN_AUTH) 89525b54dbaSEd Tanous { 8960fda0f12SGeorge Liu messages::actionNotSupported( 8970fda0f12SGeorge Liu asyncResp->res, 8980fda0f12SGeorge Liu "Setting XToken when xtoken-auth feature is disabled"); 899f16f6263SAlan Kuo return; 90025b54dbaSEd Tanous } 901c1019828SEd Tanous authMethodsConfig.xtoken = *auth.xToken; 90278158631SZbigniew Kurzynski } 90378158631SZbigniew Kurzynski 904c1019828SEd Tanous if (auth.tls) 905501f1e58SZbigniew Kurzynski { 90625b54dbaSEd Tanous if constexpr (!BMCWEB_MUTUAL_TLS_AUTH) 90725b54dbaSEd Tanous { 9080fda0f12SGeorge Liu messages::actionNotSupported( 9090fda0f12SGeorge Liu asyncResp->res, 9100fda0f12SGeorge Liu "Setting TLS when mutual-tls-auth feature is disabled"); 911f16f6263SAlan Kuo return; 91225b54dbaSEd Tanous } 913c1019828SEd Tanous authMethodsConfig.tls = *auth.tls; 914501f1e58SZbigniew Kurzynski } 915501f1e58SZbigniew Kurzynski 91678158631SZbigniew Kurzynski if (!authMethodsConfig.basic && !authMethodsConfig.cookie && 917501f1e58SZbigniew Kurzynski !authMethodsConfig.sessionToken && !authMethodsConfig.xtoken && 918501f1e58SZbigniew Kurzynski !authMethodsConfig.tls) 91978158631SZbigniew Kurzynski { 92078158631SZbigniew Kurzynski // Do not allow user to disable everything 92178158631SZbigniew Kurzynski messages::actionNotSupported(asyncResp->res, 92278158631SZbigniew Kurzynski "of disabling all available methods"); 92378158631SZbigniew Kurzynski return; 92478158631SZbigniew Kurzynski } 92578158631SZbigniew Kurzynski 92652cc112dSEd Tanous persistent_data::SessionStore::getInstance().updateAuthMethodsConfig( 92752cc112dSEd Tanous authMethodsConfig); 92878158631SZbigniew Kurzynski // Save configuration immediately 92952cc112dSEd Tanous persistent_data::getConfig().writeData(); 93078158631SZbigniew Kurzynski 93178158631SZbigniew Kurzynski messages::success(asyncResp->res); 93278158631SZbigniew Kurzynski } 93378158631SZbigniew Kurzynski 9348a07d286SRatan Gupta /** 9358a07d286SRatan Gupta * @brief Get the required values from the given JSON, validates the 9368a07d286SRatan Gupta * value and create the LDAP config object. 9378a07d286SRatan Gupta * @param input JSON data 9388a07d286SRatan Gupta * @param asyncResp pointer to the JSON response 9398a07d286SRatan Gupta * @param serverType Type of LDAP server(openLDAP/ActiveDirectory) 9408a07d286SRatan Gupta */ 9418a07d286SRatan Gupta 94210cb44f3SEd Tanous struct LdapPatchParams 94310cb44f3SEd Tanous { 94410cb44f3SEd Tanous std::optional<std::string> authType; 94510cb44f3SEd Tanous std::optional<std::vector<std::string>> serviceAddressList; 94610cb44f3SEd Tanous std::optional<bool> serviceEnabled; 94710cb44f3SEd Tanous std::optional<std::vector<std::string>> baseDNList; 94810cb44f3SEd Tanous std::optional<std::string> userNameAttribute; 94910cb44f3SEd Tanous std::optional<std::string> groupsAttribute; 95010cb44f3SEd Tanous std::optional<std::string> userName; 95110cb44f3SEd Tanous std::optional<std::string> password; 95210cb44f3SEd Tanous std::optional< 95310cb44f3SEd Tanous std::vector<std::variant<nlohmann::json::object_t, std::nullptr_t>>> 95410cb44f3SEd Tanous remoteRoleMapData; 95510cb44f3SEd Tanous }; 95610cb44f3SEd Tanous 95710cb44f3SEd Tanous inline void handleLDAPPatch(LdapPatchParams&& input, 9588d1b46d7Szhanghch05 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 9598a07d286SRatan Gupta const std::string& serverType) 9608a07d286SRatan Gupta { 961eb2bbe56SRatan Gupta std::string dbusObjectPath; 962eb2bbe56SRatan Gupta if (serverType == "ActiveDirectory") 963eb2bbe56SRatan Gupta { 9642c70f800SEd Tanous dbusObjectPath = adConfigObject; 965eb2bbe56SRatan Gupta } 966eb2bbe56SRatan Gupta else if (serverType == "LDAP") 967eb2bbe56SRatan Gupta { 96823a21a1cSEd Tanous dbusObjectPath = ldapConfigObjectName; 969eb2bbe56SRatan Gupta } 970cb13a392SEd Tanous else 971cb13a392SEd Tanous { 97210cb44f3SEd Tanous BMCWEB_LOG_ERROR("serverType wasn't AD or LDAP but was {}????", 97310cb44f3SEd Tanous serverType); 974cb13a392SEd Tanous return; 975cb13a392SEd Tanous } 976eb2bbe56SRatan Gupta 97710cb44f3SEd Tanous if (input.authType && *input.authType != "UsernameAndPassword") 9788a07d286SRatan Gupta { 97910cb44f3SEd Tanous messages::propertyValueNotInList(asyncResp->res, *input.authType, 980c1019828SEd Tanous "AuthenticationType"); 981c1019828SEd Tanous return; 9828a07d286SRatan Gupta } 983c1019828SEd Tanous 98410cb44f3SEd Tanous if (input.serviceAddressList) 9858a07d286SRatan Gupta { 98610cb44f3SEd Tanous if (input.serviceAddressList->empty()) 9878a07d286SRatan Gupta { 988e2616cc5SEd Tanous messages::propertyValueNotInList( 98910cb44f3SEd Tanous asyncResp->res, *input.serviceAddressList, "ServiceAddress"); 9908a07d286SRatan Gupta return; 9918a07d286SRatan Gupta } 9928a07d286SRatan Gupta } 99310cb44f3SEd Tanous if (input.baseDNList) 9948a07d286SRatan Gupta { 99510cb44f3SEd Tanous if (input.baseDNList->empty()) 9968a07d286SRatan Gupta { 99710cb44f3SEd Tanous messages::propertyValueNotInList(asyncResp->res, *input.baseDNList, 9988a07d286SRatan Gupta "BaseDistinguishedNames"); 9998a07d286SRatan Gupta return; 10008a07d286SRatan Gupta } 10018a07d286SRatan Gupta } 10028a07d286SRatan Gupta 10038a07d286SRatan Gupta // nothing to update, then return 100410cb44f3SEd Tanous if (!input.userName && !input.password && !input.serviceAddressList && 100510cb44f3SEd Tanous !input.baseDNList && !input.userNameAttribute && 100610cb44f3SEd Tanous !input.groupsAttribute && !input.serviceEnabled && 100710cb44f3SEd Tanous !input.remoteRoleMapData) 10088a07d286SRatan Gupta { 10098a07d286SRatan Gupta return; 10108a07d286SRatan Gupta } 10118a07d286SRatan Gupta 10128a07d286SRatan Gupta // Get the existing resource first then keep modifying 10138a07d286SRatan Gupta // whenever any property gets updated. 1014bd79bce8SPatrick Williams getLDAPConfigData(serverType, [asyncResp, input = std::move(input), 101510cb44f3SEd Tanous dbusObjectPath = std::move(dbusObjectPath)]( 1016bd79bce8SPatrick Williams bool success, 1017bd79bce8SPatrick Williams const LDAPConfigData& confData, 1018c1019828SEd Tanous const std::string& serverT) mutable { 10198a07d286SRatan Gupta if (!success) 10208a07d286SRatan Gupta { 10218a07d286SRatan Gupta messages::internalError(asyncResp->res); 10228a07d286SRatan Gupta return; 10238a07d286SRatan Gupta } 10246c51eab1SEd Tanous parseLDAPConfigData(asyncResp->res.jsonValue, confData, serverT); 10258a07d286SRatan Gupta if (confData.serviceEnabled) 10268a07d286SRatan Gupta { 10278a07d286SRatan Gupta // Disable the service first and update the rest of 10288a07d286SRatan Gupta // the properties. 10296c51eab1SEd Tanous handleServiceEnablePatch(false, asyncResp, serverT, dbusObjectPath); 10308a07d286SRatan Gupta } 10318a07d286SRatan Gupta 103210cb44f3SEd Tanous if (input.serviceAddressList) 10338a07d286SRatan Gupta { 103410cb44f3SEd Tanous handleServiceAddressPatch(*input.serviceAddressList, asyncResp, 103510cb44f3SEd Tanous serverT, dbusObjectPath); 103610cb44f3SEd Tanous } 103710cb44f3SEd Tanous if (input.userName) 103810cb44f3SEd Tanous { 103910cb44f3SEd Tanous handleUserNamePatch(*input.userName, asyncResp, serverT, 10406c51eab1SEd Tanous dbusObjectPath); 10418a07d286SRatan Gupta } 104210cb44f3SEd Tanous if (input.password) 10438a07d286SRatan Gupta { 104410cb44f3SEd Tanous handlePasswordPatch(*input.password, asyncResp, serverT, 104510cb44f3SEd Tanous dbusObjectPath); 10468a07d286SRatan Gupta } 10478a07d286SRatan Gupta 104810cb44f3SEd Tanous if (input.baseDNList) 10498a07d286SRatan Gupta { 105010cb44f3SEd Tanous handleBaseDNPatch(*input.baseDNList, asyncResp, serverT, 10516c51eab1SEd Tanous dbusObjectPath); 10528a07d286SRatan Gupta } 105310cb44f3SEd Tanous if (input.userNameAttribute) 10548a07d286SRatan Gupta { 105510cb44f3SEd Tanous handleUserNameAttrPatch(*input.userNameAttribute, asyncResp, 105610cb44f3SEd Tanous serverT, dbusObjectPath); 105710cb44f3SEd Tanous } 105810cb44f3SEd Tanous if (input.groupsAttribute) 105910cb44f3SEd Tanous { 106010cb44f3SEd Tanous handleGroupNameAttrPatch(*input.groupsAttribute, asyncResp, serverT, 10616c51eab1SEd Tanous dbusObjectPath); 10628a07d286SRatan Gupta } 106310cb44f3SEd Tanous if (input.serviceEnabled) 10648a07d286SRatan Gupta { 10658a07d286SRatan Gupta // if user has given the value as true then enable 10668a07d286SRatan Gupta // the service. if user has given false then no-op 10678a07d286SRatan Gupta // as service is already stopped. 106810cb44f3SEd Tanous if (*input.serviceEnabled) 10698a07d286SRatan Gupta { 107010cb44f3SEd Tanous handleServiceEnablePatch(*input.serviceEnabled, asyncResp, 107110cb44f3SEd Tanous serverT, dbusObjectPath); 10728a07d286SRatan Gupta } 10738a07d286SRatan Gupta } 10748a07d286SRatan Gupta else 10758a07d286SRatan Gupta { 10768a07d286SRatan Gupta // if user has not given the service enabled value 10778a07d286SRatan Gupta // then revert it to the same state as it was 10788a07d286SRatan Gupta // before. 10798a07d286SRatan Gupta handleServiceEnablePatch(confData.serviceEnabled, asyncResp, 108023a21a1cSEd Tanous serverT, dbusObjectPath); 10818a07d286SRatan Gupta } 108206785244SRatan Gupta 108310cb44f3SEd Tanous if (input.remoteRoleMapData) 108406785244SRatan Gupta { 10856c51eab1SEd Tanous handleRoleMapPatch(asyncResp, confData.groupRoleList, serverT, 108610cb44f3SEd Tanous *input.remoteRoleMapData); 108706785244SRatan Gupta } 10888a07d286SRatan Gupta }); 10898a07d286SRatan Gupta } 1090d4b5443fSEd Tanous 109158345856SAbhishek Patel inline void updateUserProperties( 109258345856SAbhishek Patel std::shared_ptr<bmcweb::AsyncResp> asyncResp, const std::string& username, 1093618c14b4SEd Tanous const std::optional<std::string>& password, 1094618c14b4SEd Tanous const std::optional<bool>& enabled, 109558345856SAbhishek Patel const std::optional<std::string>& roleId, const std::optional<bool>& locked, 1096e518ef32SRavi Teja std::optional<std::vector<std::string>> accountTypes, bool userSelf, 1097e518ef32SRavi Teja const std::shared_ptr<persistent_data::UserSession>& session) 10981abe55efSEd Tanous { 1099b477fd44SP Dheeraj Srujan Kumar sdbusplus::message::object_path tempObjPath(rootUserDbusPath); 1100b477fd44SP Dheeraj Srujan Kumar tempObjPath /= username; 1101b477fd44SP Dheeraj Srujan Kumar std::string dbusObjectPath(tempObjPath); 11026c51eab1SEd Tanous 11036c51eab1SEd Tanous dbus::utility::checkDbusPathExists( 1104e518ef32SRavi Teja dbusObjectPath, 1105e518ef32SRavi Teja [dbusObjectPath, username, password, roleId, enabled, locked, 1106e518ef32SRavi Teja accountTypes(std::move(accountTypes)), userSelf, session, 1107e518ef32SRavi Teja asyncResp{std::move(asyncResp)}](int rc) { 1108e662eae8SEd Tanous if (rc <= 0) 11096c51eab1SEd Tanous { 1110d8a5d5d8SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "ManagerAccount", 11116c51eab1SEd Tanous username); 11126c51eab1SEd Tanous return; 11136c51eab1SEd Tanous } 11146c51eab1SEd Tanous 11156c51eab1SEd Tanous if (password) 11166c51eab1SEd Tanous { 11176c51eab1SEd Tanous int retval = pamUpdatePassword(username, *password); 11186c51eab1SEd Tanous 11196c51eab1SEd Tanous if (retval == PAM_USER_UNKNOWN) 11206c51eab1SEd Tanous { 1121d8a5d5d8SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "ManagerAccount", 11226c51eab1SEd Tanous username); 11236c51eab1SEd Tanous } 11246c51eab1SEd Tanous else if (retval == PAM_AUTHTOK_ERR) 11256c51eab1SEd Tanous { 11266c51eab1SEd Tanous // If password is invalid 11279bd80831SJason M. Bills messages::propertyValueFormatError(asyncResp->res, nullptr, 11289bd80831SJason M. Bills "Password"); 112962598e31SEd Tanous BMCWEB_LOG_ERROR("pamUpdatePassword Failed"); 11306c51eab1SEd Tanous } 11316c51eab1SEd Tanous else if (retval != PAM_SUCCESS) 11326c51eab1SEd Tanous { 11336c51eab1SEd Tanous messages::internalError(asyncResp->res); 11346c51eab1SEd Tanous return; 11356c51eab1SEd Tanous } 1136e7b1b62bSEd Tanous else 1137e7b1b62bSEd Tanous { 1138bd79bce8SPatrick Williams // Remove existing sessions of the user when password 1139bd79bce8SPatrick Williams // changed 1140e518ef32SRavi Teja persistent_data::SessionStore::getInstance() 1141bd79bce8SPatrick Williams .removeSessionsByUsernameExceptSession(username, 1142bd79bce8SPatrick Williams session); 1143e7b1b62bSEd Tanous messages::success(asyncResp->res); 1144e7b1b62bSEd Tanous } 11456c51eab1SEd Tanous } 11466c51eab1SEd Tanous 11476c51eab1SEd Tanous if (enabled) 11486c51eab1SEd Tanous { 1149bd79bce8SPatrick Williams setDbusProperty( 1150bd79bce8SPatrick Williams asyncResp, "Enabled", "xyz.openbmc_project.User.Manager", 1151bd79bce8SPatrick Williams dbusObjectPath, "xyz.openbmc_project.User.Attributes", 1152e93abac6SGinu George "UserEnabled", *enabled); 11536c51eab1SEd Tanous } 11546c51eab1SEd Tanous 11556c51eab1SEd Tanous if (roleId) 11566c51eab1SEd Tanous { 11576c51eab1SEd Tanous std::string priv = getPrivilegeFromRoleId(*roleId); 11586c51eab1SEd Tanous if (priv.empty()) 11596c51eab1SEd Tanous { 1160e2616cc5SEd Tanous messages::propertyValueNotInList(asyncResp->res, true, 1161e2616cc5SEd Tanous "Locked"); 11626c51eab1SEd Tanous return; 11636c51eab1SEd Tanous } 1164bd79bce8SPatrick Williams setDbusProperty( 1165bd79bce8SPatrick Williams asyncResp, "RoleId", "xyz.openbmc_project.User.Manager", 1166bd79bce8SPatrick Williams dbusObjectPath, "xyz.openbmc_project.User.Attributes", 1167e93abac6SGinu George "UserPrivilege", priv); 11686c51eab1SEd Tanous } 11696c51eab1SEd Tanous 11706c51eab1SEd Tanous if (locked) 11716c51eab1SEd Tanous { 11726c51eab1SEd Tanous // admin can unlock the account which is locked by 11736c51eab1SEd Tanous // successive authentication failures but admin should 11746c51eab1SEd Tanous // not be allowed to lock an account. 11756c51eab1SEd Tanous if (*locked) 11766c51eab1SEd Tanous { 11776c51eab1SEd Tanous messages::propertyValueNotInList(asyncResp->res, "true", 11786c51eab1SEd Tanous "Locked"); 11796c51eab1SEd Tanous return; 11806c51eab1SEd Tanous } 1181bd79bce8SPatrick Williams setDbusProperty( 1182bd79bce8SPatrick Williams asyncResp, "Locked", "xyz.openbmc_project.User.Manager", 1183bd79bce8SPatrick Williams dbusObjectPath, "xyz.openbmc_project.User.Attributes", 1184e93abac6SGinu George "UserLockedForFailedAttempt", *locked); 11856c51eab1SEd Tanous } 118658345856SAbhishek Patel 118758345856SAbhishek Patel if (accountTypes) 118858345856SAbhishek Patel { 118958345856SAbhishek Patel patchAccountTypes(*accountTypes, asyncResp, dbusObjectPath, 119058345856SAbhishek Patel userSelf); 119158345856SAbhishek Patel } 11926c51eab1SEd Tanous }); 11936c51eab1SEd Tanous } 11946c51eab1SEd Tanous 11954c7d4d33SEd Tanous inline void handleAccountServiceHead( 11964c7d4d33SEd Tanous App& app, const crow::Request& req, 11971ef4c342SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 11986c51eab1SEd Tanous { 11993ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 120045ca1b86SEd Tanous { 120145ca1b86SEd Tanous return; 120245ca1b86SEd Tanous } 12034c7d4d33SEd Tanous asyncResp->res.addHeader( 12044c7d4d33SEd Tanous boost::beast::http::field::link, 12054c7d4d33SEd Tanous "</redfish/v1/JsonSchemas/AccountService/AccountService.json>; rel=describedby"); 12064c7d4d33SEd Tanous } 12074c7d4d33SEd Tanous 12084c7d4d33SEd Tanous inline void 12091aa375b8SEd Tanous getClientCertificates(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 12101aa375b8SEd Tanous const nlohmann::json::json_pointer& keyLocation) 12111aa375b8SEd Tanous { 12121aa375b8SEd Tanous boost::urls::url url( 12131aa375b8SEd Tanous "/redfish/v1/AccountService/MultiFactorAuth/ClientCertificate/Certificates"); 12141aa375b8SEd Tanous std::array<std::string_view, 1> interfaces = { 12151aa375b8SEd Tanous "xyz.openbmc_project.Certs.Certificate"}; 12161aa375b8SEd Tanous std::string path = "/xyz/openbmc_project/certs/authority/truststore"; 12171aa375b8SEd Tanous 12181aa375b8SEd Tanous collection_util::getCollectionToKey(asyncResp, url, interfaces, path, 12191aa375b8SEd Tanous keyLocation); 12201aa375b8SEd Tanous } 12211aa375b8SEd Tanous 12221aa375b8SEd Tanous inline void handleAccountServiceClientCertificatesInstanceHead( 12231aa375b8SEd Tanous App& app, const crow::Request& req, 12241aa375b8SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 12251aa375b8SEd Tanous const std::string& /*id*/) 12261aa375b8SEd Tanous { 12271aa375b8SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 12281aa375b8SEd Tanous { 12291aa375b8SEd Tanous return; 12301aa375b8SEd Tanous } 12311aa375b8SEd Tanous 12321aa375b8SEd Tanous asyncResp->res.addHeader( 12331aa375b8SEd Tanous boost::beast::http::field::link, 12341aa375b8SEd Tanous "</redfish/v1/JsonSchemas/Certificate/Certificate.json>; rel=describedby"); 12351aa375b8SEd Tanous } 12361aa375b8SEd Tanous 12371aa375b8SEd Tanous inline void handleAccountServiceClientCertificatesInstanceGet( 12381aa375b8SEd Tanous App& app, const crow::Request& req, 12391aa375b8SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id) 12401aa375b8SEd Tanous { 12411aa375b8SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 12421aa375b8SEd Tanous { 12431aa375b8SEd Tanous return; 12441aa375b8SEd Tanous } 12451aa375b8SEd Tanous BMCWEB_LOG_DEBUG("ClientCertificate Certificate ID={}", id); 12461aa375b8SEd Tanous const boost::urls::url certURL = boost::urls::format( 12471aa375b8SEd Tanous "/redfish/v1/AccountService/MultiFactorAuth/ClientCertificate/Certificates/{}", 12481aa375b8SEd Tanous id); 12491aa375b8SEd Tanous std::string objPath = 12501aa375b8SEd Tanous sdbusplus::message::object_path(certs::authorityObjectPath) / id; 12511aa375b8SEd Tanous getCertificateProperties( 12521aa375b8SEd Tanous asyncResp, objPath, 12531aa375b8SEd Tanous "xyz.openbmc_project.Certs.Manager.Authority.Truststore", id, certURL, 12541aa375b8SEd Tanous "Client Certificate"); 12551aa375b8SEd Tanous } 12561aa375b8SEd Tanous 12571aa375b8SEd Tanous inline void handleAccountServiceClientCertificatesHead( 12581aa375b8SEd Tanous App& app, const crow::Request& req, 12591aa375b8SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 12601aa375b8SEd Tanous { 12611aa375b8SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 12621aa375b8SEd Tanous { 12631aa375b8SEd Tanous return; 12641aa375b8SEd Tanous } 12651aa375b8SEd Tanous 12661aa375b8SEd Tanous asyncResp->res.addHeader( 12671aa375b8SEd Tanous boost::beast::http::field::link, 12681aa375b8SEd Tanous "</redfish/v1/JsonSchemas/CertificateCollection/CertificateCollection.json>; rel=describedby"); 12691aa375b8SEd Tanous } 12701aa375b8SEd Tanous 12711aa375b8SEd Tanous inline void handleAccountServiceClientCertificatesGet( 12721aa375b8SEd Tanous App& app, const crow::Request& req, 12731aa375b8SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 12741aa375b8SEd Tanous { 12751aa375b8SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 12761aa375b8SEd Tanous { 12771aa375b8SEd Tanous return; 12781aa375b8SEd Tanous } 12791aa375b8SEd Tanous getClientCertificates(asyncResp, "/Members"_json_pointer); 12801aa375b8SEd Tanous } 12811aa375b8SEd Tanous 12823ce3688aSEd Tanous using account_service::CertificateMappingAttribute; 12833ce3688aSEd Tanous using persistent_data::MTLSCommonNameParseMode; 12843ce3688aSEd Tanous inline CertificateMappingAttribute 12853ce3688aSEd Tanous getCertificateMapping(MTLSCommonNameParseMode parse) 12863ce3688aSEd Tanous { 12873ce3688aSEd Tanous switch (parse) 12883ce3688aSEd Tanous { 12893ce3688aSEd Tanous case MTLSCommonNameParseMode::CommonName: 12903ce3688aSEd Tanous { 12913ce3688aSEd Tanous return CertificateMappingAttribute::CommonName; 12923ce3688aSEd Tanous } 12933ce3688aSEd Tanous break; 12943ce3688aSEd Tanous case MTLSCommonNameParseMode::Whole: 12953ce3688aSEd Tanous { 12963ce3688aSEd Tanous return CertificateMappingAttribute::Whole; 12973ce3688aSEd Tanous } 12983ce3688aSEd Tanous break; 12993ce3688aSEd Tanous case MTLSCommonNameParseMode::UserPrincipalName: 13003ce3688aSEd Tanous { 13013ce3688aSEd Tanous return CertificateMappingAttribute::UserPrincipalName; 13023ce3688aSEd Tanous } 13033ce3688aSEd Tanous break; 13043ce3688aSEd Tanous 13053ce3688aSEd Tanous case MTLSCommonNameParseMode::Meta: 13063ce3688aSEd Tanous { 13073ce3688aSEd Tanous if constexpr (BMCWEB_META_TLS_COMMON_NAME_PARSING) 13083ce3688aSEd Tanous { 13093ce3688aSEd Tanous return CertificateMappingAttribute::CommonName; 13103ce3688aSEd Tanous } 13113ce3688aSEd Tanous } 13123ce3688aSEd Tanous break; 13133ce3688aSEd Tanous default: 13143ce3688aSEd Tanous { 13153ce3688aSEd Tanous return CertificateMappingAttribute::Invalid; 13163ce3688aSEd Tanous } 13173ce3688aSEd Tanous break; 13183ce3688aSEd Tanous } 13193ce3688aSEd Tanous } 13203ce3688aSEd Tanous 13211aa375b8SEd Tanous inline void 13224c7d4d33SEd Tanous handleAccountServiceGet(App& app, const crow::Request& req, 13234c7d4d33SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 13244c7d4d33SEd Tanous { 1325afd369c6SJiaqing Zhao if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 1326afd369c6SJiaqing Zhao { 1327afd369c6SJiaqing Zhao return; 1328afd369c6SJiaqing Zhao } 13293e72c202SNinad Palsule 13303e72c202SNinad Palsule if (req.session == nullptr) 13313e72c202SNinad Palsule { 13323e72c202SNinad Palsule messages::internalError(asyncResp->res); 13333e72c202SNinad Palsule return; 13343e72c202SNinad Palsule } 13353e72c202SNinad Palsule 1336c1019828SEd Tanous const persistent_data::AuthConfigMethods& authMethodsConfig = 1337c1019828SEd Tanous persistent_data::SessionStore::getInstance().getAuthMethodsConfig(); 1338c1019828SEd Tanous 1339afd369c6SJiaqing Zhao asyncResp->res.addHeader( 1340afd369c6SJiaqing Zhao boost::beast::http::field::link, 1341afd369c6SJiaqing Zhao "</redfish/v1/JsonSchemas/AccountService/AccountService.json>; rel=describedby"); 1342afd369c6SJiaqing Zhao 13431476687dSEd Tanous nlohmann::json& json = asyncResp->res.jsonValue; 13441476687dSEd Tanous json["@odata.id"] = "/redfish/v1/AccountService"; 1345482a69e7SRavi Teja json["@odata.type"] = "#AccountService.v1_15_0.AccountService"; 13461476687dSEd Tanous json["Id"] = "AccountService"; 13471476687dSEd Tanous json["Name"] = "Account Service"; 13481476687dSEd Tanous json["Description"] = "Account Service"; 13491476687dSEd Tanous json["ServiceEnabled"] = true; 13501476687dSEd Tanous json["MaxPasswordLength"] = 20; 13511ef4c342SEd Tanous json["Accounts"]["@odata.id"] = "/redfish/v1/AccountService/Accounts"; 13521476687dSEd Tanous json["Roles"]["@odata.id"] = "/redfish/v1/AccountService/Roles"; 1353482a69e7SRavi Teja json["HTTPBasicAuth"] = authMethodsConfig.basic 1354482a69e7SRavi Teja ? account_service::BasicAuthState::Enabled 1355482a69e7SRavi Teja : account_service::BasicAuthState::Disabled; 1356482a69e7SRavi Teja 1357482a69e7SRavi Teja nlohmann::json::array_t allowed; 1358482a69e7SRavi Teja allowed.emplace_back(account_service::BasicAuthState::Enabled); 1359482a69e7SRavi Teja allowed.emplace_back(account_service::BasicAuthState::Disabled); 1360482a69e7SRavi Teja json["HTTPBasicAuth@AllowableValues"] = std::move(allowed); 1361482a69e7SRavi Teja 13621aa375b8SEd Tanous nlohmann::json::object_t clientCertificate; 13631aa375b8SEd Tanous clientCertificate["Enabled"] = authMethodsConfig.tls; 13643281bcf1SEd Tanous clientCertificate["RespondToUnauthenticatedClients"] = 13653281bcf1SEd Tanous !authMethodsConfig.tlsStrict; 13663ce3688aSEd Tanous 13673ce3688aSEd Tanous using account_service::CertificateMappingAttribute; 13683ce3688aSEd Tanous 13693ce3688aSEd Tanous CertificateMappingAttribute mapping = 13703ce3688aSEd Tanous getCertificateMapping(authMethodsConfig.mTLSCommonNameParsingMode); 13713ce3688aSEd Tanous if (mapping == CertificateMappingAttribute::Invalid) 13723ce3688aSEd Tanous { 13733ce3688aSEd Tanous messages::internalError(asyncResp->res); 13743ce3688aSEd Tanous } 13753ce3688aSEd Tanous else 13763ce3688aSEd Tanous { 13773ce3688aSEd Tanous clientCertificate["CertificateMappingAttribute"] = mapping; 13783ce3688aSEd Tanous } 13791aa375b8SEd Tanous nlohmann::json::object_t certificates; 13801aa375b8SEd Tanous certificates["@odata.id"] = 13811aa375b8SEd Tanous "/redfish/v1/AccountService/MultiFactorAuth/ClientCertificate/Certificates"; 13821aa375b8SEd Tanous certificates["@odata.type"] = 13831aa375b8SEd Tanous "#CertificateCollection.CertificateCollection"; 13841aa375b8SEd Tanous clientCertificate["Certificates"] = std::move(certificates); 13851aa375b8SEd Tanous json["MultiFactorAuth"]["ClientCertificate"] = std::move(clientCertificate); 13861aa375b8SEd Tanous 13871aa375b8SEd Tanous getClientCertificates( 13881aa375b8SEd Tanous asyncResp, 13891aa375b8SEd Tanous "/MultiFactorAuth/ClientCertificate/Certificates/Members"_json_pointer); 13901aa375b8SEd Tanous 13911476687dSEd Tanous json["Oem"]["OpenBMC"]["@odata.type"] = 13925b5574acSEd Tanous "#OpenBMCAccountService.v1_0_0.AccountService"; 13931476687dSEd Tanous json["Oem"]["OpenBMC"]["@odata.id"] = 13941476687dSEd Tanous "/redfish/v1/AccountService#/Oem/OpenBMC"; 13951476687dSEd Tanous json["Oem"]["OpenBMC"]["AuthMethods"]["BasicAuth"] = 13961476687dSEd Tanous authMethodsConfig.basic; 13971476687dSEd Tanous json["Oem"]["OpenBMC"]["AuthMethods"]["SessionToken"] = 13981476687dSEd Tanous authMethodsConfig.sessionToken; 13991ef4c342SEd Tanous json["Oem"]["OpenBMC"]["AuthMethods"]["XToken"] = authMethodsConfig.xtoken; 14001ef4c342SEd Tanous json["Oem"]["OpenBMC"]["AuthMethods"]["Cookie"] = authMethodsConfig.cookie; 14011ef4c342SEd Tanous json["Oem"]["OpenBMC"]["AuthMethods"]["TLS"] = authMethodsConfig.tls; 14021476687dSEd Tanous 14031ef4c342SEd Tanous // /redfish/v1/AccountService/LDAP/Certificates is something only 14041ef4c342SEd Tanous // ConfigureManager can access then only display when the user has 14051ef4c342SEd Tanous // permissions ConfigureManager 140672048780SAbhishek Patel Privileges effectiveUserPrivileges = 14073e72c202SNinad Palsule redfish::getUserPrivileges(*req.session); 140872048780SAbhishek Patel 140972048780SAbhishek Patel if (isOperationAllowedWithPrivileges({{"ConfigureManager"}}, 141072048780SAbhishek Patel effectiveUserPrivileges)) 141172048780SAbhishek Patel { 14121ef4c342SEd Tanous asyncResp->res.jsonValue["LDAP"]["Certificates"]["@odata.id"] = 14131476687dSEd Tanous "/redfish/v1/AccountService/LDAP/Certificates"; 141472048780SAbhishek Patel } 1415d1bde9e5SKrzysztof Grobelny sdbusplus::asio::getAllProperties( 1416d1bde9e5SKrzysztof Grobelny *crow::connections::systemBus, "xyz.openbmc_project.User.Manager", 1417d1bde9e5SKrzysztof Grobelny "/xyz/openbmc_project/user", "xyz.openbmc_project.User.AccountPolicy", 14185e7e2dc5SEd Tanous [asyncResp](const boost::system::error_code& ec, 14191ef4c342SEd Tanous const dbus::utility::DBusPropertiesMap& propertiesList) { 14203d958bbcSAppaRao Puli if (ec) 14213d958bbcSAppaRao Puli { 14223d958bbcSAppaRao Puli messages::internalError(asyncResp->res); 14233d958bbcSAppaRao Puli return; 14243d958bbcSAppaRao Puli } 1425d1bde9e5SKrzysztof Grobelny 142662598e31SEd Tanous BMCWEB_LOG_DEBUG("Got {} properties for AccountService", 142762598e31SEd Tanous propertiesList.size()); 1428d1bde9e5SKrzysztof Grobelny 1429d1bde9e5SKrzysztof Grobelny const uint8_t* minPasswordLength = nullptr; 1430d1bde9e5SKrzysztof Grobelny const uint32_t* accountUnlockTimeout = nullptr; 1431d1bde9e5SKrzysztof Grobelny const uint16_t* maxLoginAttemptBeforeLockout = nullptr; 1432d1bde9e5SKrzysztof Grobelny 1433d1bde9e5SKrzysztof Grobelny const bool success = sdbusplus::unpackPropertiesNoThrow( 1434d1bde9e5SKrzysztof Grobelny dbus_utils::UnpackErrorPrinter(), propertiesList, 1435d1bde9e5SKrzysztof Grobelny "MinPasswordLength", minPasswordLength, "AccountUnlockTimeout", 1436d1bde9e5SKrzysztof Grobelny accountUnlockTimeout, "MaxLoginAttemptBeforeLockout", 1437d1bde9e5SKrzysztof Grobelny maxLoginAttemptBeforeLockout); 1438d1bde9e5SKrzysztof Grobelny 1439d1bde9e5SKrzysztof Grobelny if (!success) 14403d958bbcSAppaRao Puli { 1441d1bde9e5SKrzysztof Grobelny messages::internalError(asyncResp->res); 1442d1bde9e5SKrzysztof Grobelny return; 14433d958bbcSAppaRao Puli } 1444d1bde9e5SKrzysztof Grobelny 1445d1bde9e5SKrzysztof Grobelny if (minPasswordLength != nullptr) 14463d958bbcSAppaRao Puli { 1447bd79bce8SPatrick Williams asyncResp->res.jsonValue["MinPasswordLength"] = 1448bd79bce8SPatrick Williams *minPasswordLength; 14493d958bbcSAppaRao Puli } 1450d1bde9e5SKrzysztof Grobelny 1451d1bde9e5SKrzysztof Grobelny if (accountUnlockTimeout != nullptr) 14523d958bbcSAppaRao Puli { 1453d1bde9e5SKrzysztof Grobelny asyncResp->res.jsonValue["AccountLockoutDuration"] = 1454d1bde9e5SKrzysztof Grobelny *accountUnlockTimeout; 1455d1bde9e5SKrzysztof Grobelny } 1456d1bde9e5SKrzysztof Grobelny 1457d1bde9e5SKrzysztof Grobelny if (maxLoginAttemptBeforeLockout != nullptr) 14583d958bbcSAppaRao Puli { 1459002d39b4SEd Tanous asyncResp->res.jsonValue["AccountLockoutThreshold"] = 1460d1bde9e5SKrzysztof Grobelny *maxLoginAttemptBeforeLockout; 14613d958bbcSAppaRao Puli } 1462d1bde9e5SKrzysztof Grobelny }); 14636973a582SRatan Gupta 146402cad96eSEd Tanous auto callback = [asyncResp](bool success, const LDAPConfigData& confData, 1465ab828d7cSRatan Gupta const std::string& ldapType) { 1466cb13a392SEd Tanous if (!success) 1467cb13a392SEd Tanous { 1468cb13a392SEd Tanous return; 1469cb13a392SEd Tanous } 1470002d39b4SEd Tanous parseLDAPConfigData(asyncResp->res.jsonValue, confData, ldapType); 1471ab828d7cSRatan Gupta }; 1472ab828d7cSRatan Gupta 1473ab828d7cSRatan Gupta getLDAPConfigData("LDAP", callback); 1474ab828d7cSRatan Gupta getLDAPConfigData("ActiveDirectory", callback); 14751ef4c342SEd Tanous } 14766973a582SRatan Gupta 1477bd79bce8SPatrick Williams inline void handleCertificateMappingAttributePatch( 1478bd79bce8SPatrick Williams crow::Response& res, const std::string& certMapAttribute) 14793ce3688aSEd Tanous { 14803ce3688aSEd Tanous MTLSCommonNameParseMode parseMode = 14813ce3688aSEd Tanous persistent_data::getMTLSCommonNameParseMode(certMapAttribute); 14823ce3688aSEd Tanous if (parseMode == MTLSCommonNameParseMode::Invalid) 14833ce3688aSEd Tanous { 14843ce3688aSEd Tanous messages::propertyValueNotInList(res, "CertificateMappingAttribute", 14853ce3688aSEd Tanous certMapAttribute); 14863ce3688aSEd Tanous return; 14873ce3688aSEd Tanous } 14883ce3688aSEd Tanous 14893ce3688aSEd Tanous persistent_data::AuthConfigMethods& authMethodsConfig = 14903ce3688aSEd Tanous persistent_data::SessionStore::getInstance().getAuthMethodsConfig(); 14913ce3688aSEd Tanous authMethodsConfig.mTLSCommonNameParsingMode = parseMode; 14923ce3688aSEd Tanous } 14933ce3688aSEd Tanous 14943281bcf1SEd Tanous inline void handleRespondToUnauthenticatedClientsPatch( 14953281bcf1SEd Tanous App& app, const crow::Request& req, crow::Response& res, 14963281bcf1SEd Tanous bool respondToUnauthenticatedClients) 14973281bcf1SEd Tanous { 14983281bcf1SEd Tanous if (req.session != nullptr) 14993281bcf1SEd Tanous { 15003281bcf1SEd Tanous // Sanity check. If the user isn't currently authenticated with mutual 15013281bcf1SEd Tanous // TLS, they very likely are about to permanently lock themselves out. 15023281bcf1SEd Tanous // Make sure they're using mutual TLS before allowing locking. 15033281bcf1SEd Tanous if (req.session->sessionType != persistent_data::SessionType::MutualTLS) 15043281bcf1SEd Tanous { 15053281bcf1SEd Tanous messages::propertyValueExternalConflict( 15063281bcf1SEd Tanous res, 15073281bcf1SEd Tanous "MultiFactorAuth/ClientCertificate/RespondToUnauthenticatedClients", 15083281bcf1SEd Tanous respondToUnauthenticatedClients); 15093281bcf1SEd Tanous return; 15103281bcf1SEd Tanous } 15113281bcf1SEd Tanous } 15123281bcf1SEd Tanous 15133281bcf1SEd Tanous persistent_data::AuthConfigMethods& authMethodsConfig = 15143281bcf1SEd Tanous persistent_data::SessionStore::getInstance().getAuthMethodsConfig(); 15153281bcf1SEd Tanous 15163281bcf1SEd Tanous // Change the settings 15173281bcf1SEd Tanous authMethodsConfig.tlsStrict = !respondToUnauthenticatedClients; 15183281bcf1SEd Tanous 15193281bcf1SEd Tanous // Write settings to disk 15203281bcf1SEd Tanous persistent_data::getConfig().writeData(); 15213281bcf1SEd Tanous 15223281bcf1SEd Tanous // Trigger a reload, to apply the new settings to new connections 15233281bcf1SEd Tanous app.loadCertificate(); 15243281bcf1SEd Tanous } 15253281bcf1SEd Tanous 15261ef4c342SEd Tanous inline void handleAccountServicePatch( 15271ef4c342SEd Tanous App& app, const crow::Request& req, 15281ef4c342SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 15291ef4c342SEd Tanous { 15303ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 153145ca1b86SEd Tanous { 153245ca1b86SEd Tanous return; 153345ca1b86SEd Tanous } 1534f5ffd806SEd Tanous std::optional<uint32_t> unlockTimeout; 1535f5ffd806SEd Tanous std::optional<uint16_t> lockoutThreshold; 1536ef73ad0dSPaul Fertser std::optional<uint8_t> minPasswordLength; 1537f5ffd806SEd Tanous std::optional<uint16_t> maxPasswordLength; 153810cb44f3SEd Tanous LdapPatchParams ldapObject; 15393ce3688aSEd Tanous std::optional<std::string> certificateMappingAttribute; 15403281bcf1SEd Tanous std::optional<bool> respondToUnauthenticatedClients; 154110cb44f3SEd Tanous LdapPatchParams activeDirectoryObject; 1542c1019828SEd Tanous AuthMethods auth; 1543482a69e7SRavi Teja std::optional<std::string> httpBasicAuth; 15443ce3688aSEd Tanous 1545c1019828SEd Tanous // clang-format off 154615ed6780SWilly Tu if (!json_util::readJsonPatch( 1547c1019828SEd Tanous req, asyncResp->res, 1548c1019828SEd Tanous "AccountLockoutDuration", unlockTimeout, 1549c1019828SEd Tanous "AccountLockoutThreshold", lockoutThreshold, 155010cb44f3SEd Tanous "ActiveDirectory/Authentication/AuthenticationType", activeDirectoryObject.authType, 155110cb44f3SEd Tanous "ActiveDirectory/Authentication/Password", activeDirectoryObject.password, 155210cb44f3SEd Tanous "ActiveDirectory/Authentication/Username", activeDirectoryObject.userName, 155310cb44f3SEd Tanous "ActiveDirectory/LDAPService/SearchSettings/BaseDistinguishedNames", activeDirectoryObject.baseDNList, 155410cb44f3SEd Tanous "ActiveDirectory/LDAPService/SearchSettings/GroupsAttribute", activeDirectoryObject.groupsAttribute, 155510cb44f3SEd Tanous "ActiveDirectory/LDAPService/SearchSettings/UsernameAttribute", activeDirectoryObject.userNameAttribute, 155610cb44f3SEd Tanous "ActiveDirectory/RemoteRoleMapping", activeDirectoryObject.remoteRoleMapData, 155710cb44f3SEd Tanous "ActiveDirectory/ServiceAddresses", activeDirectoryObject.serviceAddressList, 155810cb44f3SEd Tanous "ActiveDirectory/ServiceEnabled", activeDirectoryObject.serviceEnabled, 15593ce3688aSEd Tanous "MultiFactorAuth/ClientCertificate/CertificateMappingAttribute", certificateMappingAttribute, 15603281bcf1SEd Tanous "MultiFactorAuth/ClientCertificate/RespondToUnauthenticatedClients", respondToUnauthenticatedClients, 156110cb44f3SEd Tanous "LDAP/Authentication/AuthenticationType", ldapObject.authType, 156210cb44f3SEd Tanous "LDAP/Authentication/Password", ldapObject.password, 156310cb44f3SEd Tanous "LDAP/Authentication/Username", ldapObject.userName, 156410cb44f3SEd Tanous "LDAP/LDAPService/SearchSettings/BaseDistinguishedNames", ldapObject.baseDNList, 156510cb44f3SEd Tanous "LDAP/LDAPService/SearchSettings/GroupsAttribute", ldapObject.groupsAttribute, 156610cb44f3SEd Tanous "LDAP/LDAPService/SearchSettings/UsernameAttribute", ldapObject.userNameAttribute, 156710cb44f3SEd Tanous "LDAP/RemoteRoleMapping", ldapObject.remoteRoleMapData, 156810cb44f3SEd Tanous "LDAP/ServiceAddresses", ldapObject.serviceAddressList, 156910cb44f3SEd Tanous "LDAP/ServiceEnabled", ldapObject.serviceEnabled, 1570c1019828SEd Tanous "MaxPasswordLength", maxPasswordLength, 1571c1019828SEd Tanous "MinPasswordLength", minPasswordLength, 1572c1019828SEd Tanous "Oem/OpenBMC/AuthMethods/BasicAuth", auth.basicAuth, 1573c1019828SEd Tanous "Oem/OpenBMC/AuthMethods/Cookie", auth.cookie, 1574c1019828SEd Tanous "Oem/OpenBMC/AuthMethods/SessionToken", auth.sessionToken, 157510cb44f3SEd Tanous "Oem/OpenBMC/AuthMethods/TLS", auth.tls, 1576482a69e7SRavi Teja "Oem/OpenBMC/AuthMethods/XToken", auth.xToken, 1577482a69e7SRavi Teja "HTTPBasicAuth", httpBasicAuth)) 1578f5ffd806SEd Tanous { 1579f5ffd806SEd Tanous return; 1580f5ffd806SEd Tanous } 1581c1019828SEd Tanous // clang-format on 1582f5ffd806SEd Tanous 1583482a69e7SRavi Teja if (httpBasicAuth) 1584482a69e7SRavi Teja { 1585482a69e7SRavi Teja if (*httpBasicAuth == "Enabled") 1586482a69e7SRavi Teja { 1587482a69e7SRavi Teja auth.basicAuth = true; 1588482a69e7SRavi Teja } 1589482a69e7SRavi Teja else if (*httpBasicAuth == "Disabled") 1590482a69e7SRavi Teja { 1591482a69e7SRavi Teja auth.basicAuth = false; 1592482a69e7SRavi Teja } 1593482a69e7SRavi Teja else 1594482a69e7SRavi Teja { 1595482a69e7SRavi Teja messages::propertyValueNotInList(asyncResp->res, "HttpBasicAuth", 1596482a69e7SRavi Teja *httpBasicAuth); 1597482a69e7SRavi Teja } 1598482a69e7SRavi Teja } 1599482a69e7SRavi Teja 16003281bcf1SEd Tanous if (respondToUnauthenticatedClients) 16013281bcf1SEd Tanous { 16023281bcf1SEd Tanous handleRespondToUnauthenticatedClientsPatch( 16033281bcf1SEd Tanous app, req, asyncResp->res, *respondToUnauthenticatedClients); 16043281bcf1SEd Tanous } 16053281bcf1SEd Tanous 16063ce3688aSEd Tanous if (certificateMappingAttribute) 16073ce3688aSEd Tanous { 16083ce3688aSEd Tanous handleCertificateMappingAttributePatch(asyncResp->res, 16093ce3688aSEd Tanous *certificateMappingAttribute); 16103ce3688aSEd Tanous } 16113ce3688aSEd Tanous 1612f5ffd806SEd Tanous if (minPasswordLength) 1613f5ffd806SEd Tanous { 1614d02aad39SEd Tanous setDbusProperty( 1615e93abac6SGinu George asyncResp, "MinPasswordLength", "xyz.openbmc_project.User.Manager", 1616d02aad39SEd Tanous sdbusplus::message::object_path("/xyz/openbmc_project/user"), 16179ae226faSGeorge Liu "xyz.openbmc_project.User.AccountPolicy", "MinPasswordLength", 1618e93abac6SGinu George *minPasswordLength); 1619f5ffd806SEd Tanous } 1620f5ffd806SEd Tanous 1621f5ffd806SEd Tanous if (maxPasswordLength) 1622f5ffd806SEd Tanous { 16231ef4c342SEd Tanous messages::propertyNotWritable(asyncResp->res, "MaxPasswordLength"); 1624f5ffd806SEd Tanous } 1625f5ffd806SEd Tanous 162610cb44f3SEd Tanous handleLDAPPatch(std::move(activeDirectoryObject), asyncResp, 162710cb44f3SEd Tanous "ActiveDirectory"); 162810cb44f3SEd Tanous handleLDAPPatch(std::move(ldapObject), asyncResp, "LDAP"); 1629f5ffd806SEd Tanous 1630c1019828SEd Tanous handleAuthMethodsPatch(asyncResp, auth); 1631f5ffd806SEd Tanous 1632f5ffd806SEd Tanous if (unlockTimeout) 1633f5ffd806SEd Tanous { 1634d02aad39SEd Tanous setDbusProperty( 1635e93abac6SGinu George asyncResp, "AccountLockoutDuration", 1636e93abac6SGinu George "xyz.openbmc_project.User.Manager", 1637d02aad39SEd Tanous sdbusplus::message::object_path("/xyz/openbmc_project/user"), 16389ae226faSGeorge Liu "xyz.openbmc_project.User.AccountPolicy", "AccountUnlockTimeout", 1639e93abac6SGinu George *unlockTimeout); 1640f5ffd806SEd Tanous } 1641f5ffd806SEd Tanous if (lockoutThreshold) 1642f5ffd806SEd Tanous { 1643d02aad39SEd Tanous setDbusProperty( 1644e93abac6SGinu George asyncResp, "AccountLockoutThreshold", 1645e93abac6SGinu George "xyz.openbmc_project.User.Manager", 1646d02aad39SEd Tanous sdbusplus::message::object_path("/xyz/openbmc_project/user"), 16479ae226faSGeorge Liu "xyz.openbmc_project.User.AccountPolicy", 1648e93abac6SGinu George "MaxLoginAttemptBeforeLockout", *lockoutThreshold); 1649f5ffd806SEd Tanous } 16501ef4c342SEd Tanous } 1651f5ffd806SEd Tanous 16524c7d4d33SEd Tanous inline void handleAccountCollectionHead( 16531ef4c342SEd Tanous App& app, const crow::Request& req, 16541ef4c342SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 16551ef4c342SEd Tanous { 16563ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 165745ca1b86SEd Tanous { 165845ca1b86SEd Tanous return; 165945ca1b86SEd Tanous } 16604c7d4d33SEd Tanous asyncResp->res.addHeader( 16614c7d4d33SEd Tanous boost::beast::http::field::link, 16624c7d4d33SEd Tanous "</redfish/v1/JsonSchemas/ManagerAccountCollection.json>; rel=describedby"); 16634c7d4d33SEd Tanous } 16644c7d4d33SEd Tanous 16654c7d4d33SEd Tanous inline void handleAccountCollectionGet( 16664c7d4d33SEd Tanous App& app, const crow::Request& req, 16674c7d4d33SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 16684c7d4d33SEd Tanous { 1669afd369c6SJiaqing Zhao if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 1670afd369c6SJiaqing Zhao { 1671afd369c6SJiaqing Zhao return; 1672afd369c6SJiaqing Zhao } 16733e72c202SNinad Palsule 16743e72c202SNinad Palsule if (req.session == nullptr) 16753e72c202SNinad Palsule { 16763e72c202SNinad Palsule messages::internalError(asyncResp->res); 16773e72c202SNinad Palsule return; 16783e72c202SNinad Palsule } 16793e72c202SNinad Palsule 1680afd369c6SJiaqing Zhao asyncResp->res.addHeader( 1681afd369c6SJiaqing Zhao boost::beast::http::field::link, 1682afd369c6SJiaqing Zhao "</redfish/v1/JsonSchemas/ManagerAccountCollection.json>; rel=describedby"); 16831476687dSEd Tanous 16841476687dSEd Tanous asyncResp->res.jsonValue["@odata.id"] = 16851476687dSEd Tanous "/redfish/v1/AccountService/Accounts"; 16861ef4c342SEd Tanous asyncResp->res.jsonValue["@odata.type"] = "#ManagerAccountCollection." 16871476687dSEd Tanous "ManagerAccountCollection"; 16881476687dSEd Tanous asyncResp->res.jsonValue["Name"] = "Accounts Collection"; 16891476687dSEd Tanous asyncResp->res.jsonValue["Description"] = "BMC User Accounts"; 16900f74e643SEd Tanous 16916c51eab1SEd Tanous Privileges effectiveUserPrivileges = 16923e72c202SNinad Palsule redfish::getUserPrivileges(*req.session); 16936c51eab1SEd Tanous 1694f5e29f33SJunLin Chen std::string thisUser; 1695f5e29f33SJunLin Chen if (req.session) 1696f5e29f33SJunLin Chen { 1697f5e29f33SJunLin Chen thisUser = req.session->username; 1698f5e29f33SJunLin Chen } 16995eb468daSGeorge Liu sdbusplus::message::object_path path("/xyz/openbmc_project/user"); 17005eb468daSGeorge Liu dbus::utility::getManagedObjects( 17015eb468daSGeorge Liu "xyz.openbmc_project.User.Manager", path, 1702cef1ddfbSEd Tanous [asyncResp, thisUser, effectiveUserPrivileges]( 17035e7e2dc5SEd Tanous const boost::system::error_code& ec, 1704711ac7a9SEd Tanous const dbus::utility::ManagedObjectType& users) { 1705b9b2e0b2SEd Tanous if (ec) 1706b9b2e0b2SEd Tanous { 1707f12894f8SJason M. Bills messages::internalError(asyncResp->res); 1708b9b2e0b2SEd Tanous return; 1709b9b2e0b2SEd Tanous } 1710b9b2e0b2SEd Tanous 1711cef1ddfbSEd Tanous bool userCanSeeAllAccounts = 1712002d39b4SEd Tanous effectiveUserPrivileges.isSupersetOf({"ConfigureUsers"}); 1713cef1ddfbSEd Tanous 1714cef1ddfbSEd Tanous bool userCanSeeSelf = 1715002d39b4SEd Tanous effectiveUserPrivileges.isSupersetOf({"ConfigureSelf"}); 1716cef1ddfbSEd Tanous 1717002d39b4SEd Tanous nlohmann::json& memberArray = asyncResp->res.jsonValue["Members"]; 1718b9b2e0b2SEd Tanous memberArray = nlohmann::json::array(); 1719b9b2e0b2SEd Tanous 17209eb808c1SEd Tanous for (const auto& userpath : users) 1721b9b2e0b2SEd Tanous { 17222dfd18efSEd Tanous std::string user = userpath.first.filename(); 17232dfd18efSEd Tanous if (user.empty()) 1724b9b2e0b2SEd Tanous { 17252dfd18efSEd Tanous messages::internalError(asyncResp->res); 172662598e31SEd Tanous BMCWEB_LOG_ERROR("Invalid firmware ID"); 17272dfd18efSEd Tanous 17282dfd18efSEd Tanous return; 1729b9b2e0b2SEd Tanous } 1730f365910cSGunnar Mills 1731f365910cSGunnar Mills // As clarified by Redfish here: 1732f365910cSGunnar Mills // https://redfishforum.com/thread/281/manageraccountcollection-change-allows-account-enumeration 17336c51eab1SEd Tanous // Users without ConfigureUsers, only see their own 17346c51eab1SEd Tanous // account. Users with ConfigureUsers, see all 17356c51eab1SEd Tanous // accounts. 1736bd79bce8SPatrick Williams if (userCanSeeAllAccounts || 1737bd79bce8SPatrick Williams (thisUser == user && userCanSeeSelf)) 1738f365910cSGunnar Mills { 17391476687dSEd Tanous nlohmann::json::object_t member; 17403b32780dSEd Tanous member["@odata.id"] = boost::urls::format( 17413b32780dSEd Tanous "/redfish/v1/AccountService/Accounts/{}", user); 1742b2ba3072SPatrick Williams memberArray.emplace_back(std::move(member)); 1743b9b2e0b2SEd Tanous } 1744f365910cSGunnar Mills } 1745bd79bce8SPatrick Williams asyncResp->res.jsonValue["Members@odata.count"] = 1746bd79bce8SPatrick Williams memberArray.size(); 17475eb468daSGeorge Liu }); 17481ef4c342SEd Tanous } 17496c51eab1SEd Tanous 175097e90da3SNinad Palsule inline void processAfterCreateUser( 175197e90da3SNinad Palsule const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 175297e90da3SNinad Palsule const std::string& username, const std::string& password, 175397e90da3SNinad Palsule const boost::system::error_code& ec, sdbusplus::message_t& m) 175497e90da3SNinad Palsule { 175597e90da3SNinad Palsule if (ec) 175697e90da3SNinad Palsule { 175797e90da3SNinad Palsule userErrorMessageHandler(m.get_error(), asyncResp, username, ""); 175897e90da3SNinad Palsule return; 175997e90da3SNinad Palsule } 176097e90da3SNinad Palsule 176197e90da3SNinad Palsule if (pamUpdatePassword(username, password) != PAM_SUCCESS) 176297e90da3SNinad Palsule { 176397e90da3SNinad Palsule // At this point we have a user that's been 176497e90da3SNinad Palsule // created, but the password set 176597e90da3SNinad Palsule // failed.Something is wrong, so delete the user 176697e90da3SNinad Palsule // that we've already created 176797e90da3SNinad Palsule sdbusplus::message::object_path tempObjPath(rootUserDbusPath); 176897e90da3SNinad Palsule tempObjPath /= username; 176997e90da3SNinad Palsule const std::string userPath(tempObjPath); 177097e90da3SNinad Palsule 177197e90da3SNinad Palsule crow::connections::systemBus->async_method_call( 177297e90da3SNinad Palsule [asyncResp, password](const boost::system::error_code& ec3) { 177397e90da3SNinad Palsule if (ec3) 177497e90da3SNinad Palsule { 177597e90da3SNinad Palsule messages::internalError(asyncResp->res); 177697e90da3SNinad Palsule return; 177797e90da3SNinad Palsule } 177897e90da3SNinad Palsule 177997e90da3SNinad Palsule // If password is invalid 17809bd80831SJason M. Bills messages::propertyValueFormatError(asyncResp->res, nullptr, 178197e90da3SNinad Palsule "Password"); 178297e90da3SNinad Palsule }, 178397e90da3SNinad Palsule "xyz.openbmc_project.User.Manager", userPath, 178497e90da3SNinad Palsule "xyz.openbmc_project.Object.Delete", "Delete"); 178597e90da3SNinad Palsule 178662598e31SEd Tanous BMCWEB_LOG_ERROR("pamUpdatePassword Failed"); 178797e90da3SNinad Palsule return; 178897e90da3SNinad Palsule } 178997e90da3SNinad Palsule 179097e90da3SNinad Palsule messages::created(asyncResp->res); 179197e90da3SNinad Palsule asyncResp->res.addHeader("Location", 179297e90da3SNinad Palsule "/redfish/v1/AccountService/Accounts/" + username); 179397e90da3SNinad Palsule } 179497e90da3SNinad Palsule 179597e90da3SNinad Palsule inline void processAfterGetAllGroups( 179697e90da3SNinad Palsule const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 179797e90da3SNinad Palsule const std::string& username, const std::string& password, 1798e01d0c36SEd Tanous const std::string& roleId, bool enabled, 17999ba73934SNinad Palsule std::optional<std::vector<std::string>> accountTypes, 180097e90da3SNinad Palsule const std::vector<std::string>& allGroupsList) 180197e90da3SNinad Palsule { 18023e72c202SNinad Palsule std::vector<std::string> userGroups; 18039ba73934SNinad Palsule std::vector<std::string> accountTypeUserGroups; 18049ba73934SNinad Palsule 18059ba73934SNinad Palsule // If user specified account types then convert them to unix user groups 18069ba73934SNinad Palsule if (accountTypes) 18079ba73934SNinad Palsule { 18089ba73934SNinad Palsule if (!getUserGroupFromAccountType(asyncResp->res, *accountTypes, 18099ba73934SNinad Palsule accountTypeUserGroups)) 18109ba73934SNinad Palsule { 18119ba73934SNinad Palsule // Problem in mapping Account Types to User Groups, Error already 18129ba73934SNinad Palsule // logged. 18139ba73934SNinad Palsule return; 18149ba73934SNinad Palsule } 18159ba73934SNinad Palsule } 18169ba73934SNinad Palsule 18173e72c202SNinad Palsule for (const auto& grp : allGroupsList) 18183e72c202SNinad Palsule { 18199ba73934SNinad Palsule // If user specified the account type then only accept groups which are 18209ba73934SNinad Palsule // in the account types group list. 18219ba73934SNinad Palsule if (!accountTypeUserGroups.empty()) 18229ba73934SNinad Palsule { 18239ba73934SNinad Palsule bool found = false; 18249ba73934SNinad Palsule for (const auto& grp1 : accountTypeUserGroups) 18259ba73934SNinad Palsule { 18269ba73934SNinad Palsule if (grp == grp1) 18279ba73934SNinad Palsule { 18289ba73934SNinad Palsule found = true; 18299ba73934SNinad Palsule break; 18309ba73934SNinad Palsule } 18319ba73934SNinad Palsule } 18329ba73934SNinad Palsule if (!found) 18339ba73934SNinad Palsule { 18349ba73934SNinad Palsule continue; 18359ba73934SNinad Palsule } 18369ba73934SNinad Palsule } 18379ba73934SNinad Palsule 18383e72c202SNinad Palsule // Console access is provided to the user who is a member of 18393e72c202SNinad Palsule // hostconsole group and has a administrator role. So, set 18403e72c202SNinad Palsule // hostconsole group only for the administrator. 18419ba73934SNinad Palsule if ((grp == "hostconsole") && (roleId != "priv-admin")) 18423e72c202SNinad Palsule { 18439ba73934SNinad Palsule if (!accountTypeUserGroups.empty()) 18449ba73934SNinad Palsule { 184562598e31SEd Tanous BMCWEB_LOG_ERROR( 184662598e31SEd Tanous "Only administrator can get HostConsole access"); 18479ba73934SNinad Palsule asyncResp->res.result(boost::beast::http::status::bad_request); 18489ba73934SNinad Palsule return; 18499ba73934SNinad Palsule } 18509ba73934SNinad Palsule continue; 18519ba73934SNinad Palsule } 18523e72c202SNinad Palsule userGroups.emplace_back(grp); 18533e72c202SNinad Palsule } 18549ba73934SNinad Palsule 18559ba73934SNinad Palsule // Make sure user specified groups are valid. This is internal error because 18569ba73934SNinad Palsule // it some inconsistencies between user manager and bmcweb. 18579ba73934SNinad Palsule if (!accountTypeUserGroups.empty() && 18589ba73934SNinad Palsule accountTypeUserGroups.size() != userGroups.size()) 18599ba73934SNinad Palsule { 18609ba73934SNinad Palsule messages::internalError(asyncResp->res); 18619ba73934SNinad Palsule return; 18623e72c202SNinad Palsule } 186397e90da3SNinad Palsule crow::connections::systemBus->async_method_call( 186497e90da3SNinad Palsule [asyncResp, username, password](const boost::system::error_code& ec2, 186597e90da3SNinad Palsule sdbusplus::message_t& m) { 186697e90da3SNinad Palsule processAfterCreateUser(asyncResp, username, password, ec2, m); 186797e90da3SNinad Palsule }, 186897e90da3SNinad Palsule "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user", 18693e72c202SNinad Palsule "xyz.openbmc_project.User.Manager", "CreateUser", username, userGroups, 1870e01d0c36SEd Tanous roleId, enabled); 187197e90da3SNinad Palsule } 187297e90da3SNinad Palsule 18731ef4c342SEd Tanous inline void handleAccountCollectionPost( 18741ef4c342SEd Tanous App& app, const crow::Request& req, 18751ef4c342SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 18761ef4c342SEd Tanous { 18773ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 187845ca1b86SEd Tanous { 187945ca1b86SEd Tanous return; 188045ca1b86SEd Tanous } 18819712f8acSEd Tanous std::string username; 18829712f8acSEd Tanous std::string password; 1883e01d0c36SEd Tanous std::optional<std::string> roleIdJson; 1884e01d0c36SEd Tanous std::optional<bool> enabledJson; 18859ba73934SNinad Palsule std::optional<std::vector<std::string>> accountTypes; 1886bd79bce8SPatrick Williams if (!json_util::readJsonPatch( 1887bd79bce8SPatrick Williams req, asyncResp->res, "UserName", username, "Password", password, 1888bd79bce8SPatrick Williams "RoleId", roleIdJson, "Enabled", enabledJson, "AccountTypes", 1889e01d0c36SEd Tanous accountTypes)) 189004ae99ecSEd Tanous { 189104ae99ecSEd Tanous return; 189204ae99ecSEd Tanous } 189304ae99ecSEd Tanous 1894e01d0c36SEd Tanous std::string roleId = roleIdJson.value_or("User"); 1895e01d0c36SEd Tanous std::string priv = getPrivilegeFromRoleId(roleId); 189684e12cb7SAppaRao Puli if (priv.empty()) 189704ae99ecSEd Tanous { 1898e01d0c36SEd Tanous messages::propertyValueNotInList(asyncResp->res, roleId, "RoleId"); 189904ae99ecSEd Tanous return; 190004ae99ecSEd Tanous } 19019712f8acSEd Tanous roleId = priv; 190204ae99ecSEd Tanous 1903e01d0c36SEd Tanous bool enabled = enabledJson.value_or(true); 1904e01d0c36SEd Tanous 1905599c71d8SAyushi Smriti // Reading AllGroups property 19061e1e598dSJonathan Doman sdbusplus::asio::getProperty<std::vector<std::string>>( 19071ef4c342SEd Tanous *crow::connections::systemBus, "xyz.openbmc_project.User.Manager", 19081ef4c342SEd Tanous "/xyz/openbmc_project/user", "xyz.openbmc_project.User.Manager", 19091ef4c342SEd Tanous "AllGroups", 19109ba73934SNinad Palsule [asyncResp, username, password{std::move(password)}, roleId, enabled, 19119ba73934SNinad Palsule accountTypes](const boost::system::error_code& ec, 19121e1e598dSJonathan Doman const std::vector<std::string>& allGroupsList) { 1913599c71d8SAyushi Smriti if (ec) 1914599c71d8SAyushi Smriti { 1915a0735a4eSGunnar Mills BMCWEB_LOG_ERROR("D-Bus response error {}", ec); 1916599c71d8SAyushi Smriti messages::internalError(asyncResp->res); 1917599c71d8SAyushi Smriti return; 1918599c71d8SAyushi Smriti } 1919599c71d8SAyushi Smriti 19201e1e598dSJonathan Doman if (allGroupsList.empty()) 1921599c71d8SAyushi Smriti { 1922599c71d8SAyushi Smriti messages::internalError(asyncResp->res); 1923599c71d8SAyushi Smriti return; 1924599c71d8SAyushi Smriti } 1925599c71d8SAyushi Smriti 1926bd79bce8SPatrick Williams processAfterGetAllGroups(asyncResp, username, password, roleId, 1927bd79bce8SPatrick Williams enabled, accountTypes, allGroupsList); 19281e1e598dSJonathan Doman }); 19291ef4c342SEd Tanous } 1930b9b2e0b2SEd Tanous 19311ef4c342SEd Tanous inline void 19324c7d4d33SEd Tanous handleAccountHead(App& app, const crow::Request& req, 19336c51eab1SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 19344c7d4d33SEd Tanous const std::string& /*accountName*/) 19351ef4c342SEd Tanous { 19363ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 193745ca1b86SEd Tanous { 193845ca1b86SEd Tanous return; 193945ca1b86SEd Tanous } 19404c7d4d33SEd Tanous asyncResp->res.addHeader( 19414c7d4d33SEd Tanous boost::beast::http::field::link, 19424c7d4d33SEd Tanous "</redfish/v1/JsonSchemas/ManagerAccount/ManagerAccount.json>; rel=describedby"); 19434c7d4d33SEd Tanous } 1944afd369c6SJiaqing Zhao 19454c7d4d33SEd Tanous inline void 19464c7d4d33SEd Tanous handleAccountGet(App& app, const crow::Request& req, 19474c7d4d33SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 19484c7d4d33SEd Tanous const std::string& accountName) 19494c7d4d33SEd Tanous { 1950afd369c6SJiaqing Zhao if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 1951afd369c6SJiaqing Zhao { 1952afd369c6SJiaqing Zhao return; 1953afd369c6SJiaqing Zhao } 1954afd369c6SJiaqing Zhao asyncResp->res.addHeader( 1955afd369c6SJiaqing Zhao boost::beast::http::field::link, 1956afd369c6SJiaqing Zhao "</redfish/v1/JsonSchemas/ManagerAccount/ManagerAccount.json>; rel=describedby"); 1957afd369c6SJiaqing Zhao 195825b54dbaSEd Tanous if constexpr (BMCWEB_INSECURE_DISABLE_AUTH) 195925b54dbaSEd Tanous { 1960031514fbSJunLin Chen // If authentication is disabled, there are no user accounts 196125b54dbaSEd Tanous messages::resourceNotFound(asyncResp->res, "ManagerAccount", 196225b54dbaSEd Tanous accountName); 1963031514fbSJunLin Chen return; 196425b54dbaSEd Tanous } 1965afd369c6SJiaqing Zhao 1966031514fbSJunLin Chen if (req.session == nullptr) 1967031514fbSJunLin Chen { 1968031514fbSJunLin Chen messages::internalError(asyncResp->res); 1969031514fbSJunLin Chen return; 1970031514fbSJunLin Chen } 19716c51eab1SEd Tanous if (req.session->username != accountName) 1972b9b2e0b2SEd Tanous { 19736c51eab1SEd Tanous // At this point we've determined that the user is trying to 19741ef4c342SEd Tanous // modify a user that isn't them. We need to verify that they 19751ef4c342SEd Tanous // have permissions to modify other users, so re-run the auth 19761ef4c342SEd Tanous // check with the same permissions, minus ConfigureSelf. 19776c51eab1SEd Tanous Privileges effectiveUserPrivileges = 19783e72c202SNinad Palsule redfish::getUserPrivileges(*req.session); 19791ef4c342SEd Tanous Privileges requiredPermissionsToChangeNonSelf = {"ConfigureUsers", 19801ef4c342SEd Tanous "ConfigureManager"}; 19816c51eab1SEd Tanous if (!effectiveUserPrivileges.isSupersetOf( 19826c51eab1SEd Tanous requiredPermissionsToChangeNonSelf)) 1983900f9497SJoseph Reynolds { 198462598e31SEd Tanous BMCWEB_LOG_DEBUG("GET Account denied access"); 1985900f9497SJoseph Reynolds messages::insufficientPrivilege(asyncResp->res); 1986900f9497SJoseph Reynolds return; 1987900f9497SJoseph Reynolds } 1988900f9497SJoseph Reynolds } 1989900f9497SJoseph Reynolds 19905eb468daSGeorge Liu sdbusplus::message::object_path path("/xyz/openbmc_project/user"); 19915eb468daSGeorge Liu dbus::utility::getManagedObjects( 19925eb468daSGeorge Liu "xyz.openbmc_project.User.Manager", path, 19931ef4c342SEd Tanous [asyncResp, 19945e7e2dc5SEd Tanous accountName](const boost::system::error_code& ec, 1995711ac7a9SEd Tanous const dbus::utility::ManagedObjectType& users) { 1996b9b2e0b2SEd Tanous if (ec) 1997b9b2e0b2SEd Tanous { 1998f12894f8SJason M. Bills messages::internalError(asyncResp->res); 1999b9b2e0b2SEd Tanous return; 2000b9b2e0b2SEd Tanous } 20013544d2a7SEd Tanous const auto userIt = std::ranges::find_if( 200280f79a40SMichael Shen users, 200380f79a40SMichael Shen [accountName]( 2004b477fd44SP Dheeraj Srujan Kumar const std::pair<sdbusplus::message::object_path, 200580f79a40SMichael Shen dbus::utility::DBusInterfacesMap>& user) { 200655f79e6fSEd Tanous return accountName == user.first.filename(); 2007b477fd44SP Dheeraj Srujan Kumar }); 2008b9b2e0b2SEd Tanous 200984e12cb7SAppaRao Puli if (userIt == users.end()) 2010b9b2e0b2SEd Tanous { 2011002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "ManagerAccount", 2012002d39b4SEd Tanous accountName); 201384e12cb7SAppaRao Puli return; 201484e12cb7SAppaRao Puli } 20154e68c45bSAyushi Smriti 20161476687dSEd Tanous asyncResp->res.jsonValue["@odata.type"] = 201758345856SAbhishek Patel "#ManagerAccount.v1_7_0.ManagerAccount"; 20181476687dSEd Tanous asyncResp->res.jsonValue["Name"] = "User Account"; 20191476687dSEd Tanous asyncResp->res.jsonValue["Description"] = "User Account"; 20201476687dSEd Tanous asyncResp->res.jsonValue["Password"] = nullptr; 202158345856SAbhishek Patel asyncResp->res.jsonValue["StrictAccountTypes"] = true; 20224e68c45bSAyushi Smriti 202384e12cb7SAppaRao Puli for (const auto& interface : userIt->second) 202465b0dc32SEd Tanous { 2025002d39b4SEd Tanous if (interface.first == "xyz.openbmc_project.User.Attributes") 202665b0dc32SEd Tanous { 202765b0dc32SEd Tanous for (const auto& property : interface.second) 202865b0dc32SEd Tanous { 202965b0dc32SEd Tanous if (property.first == "UserEnabled") 203065b0dc32SEd Tanous { 203165b0dc32SEd Tanous const bool* userEnabled = 2032abf2add6SEd Tanous std::get_if<bool>(&property.second); 203365b0dc32SEd Tanous if (userEnabled == nullptr) 203465b0dc32SEd Tanous { 203562598e31SEd Tanous BMCWEB_LOG_ERROR("UserEnabled wasn't a bool"); 203684e12cb7SAppaRao Puli messages::internalError(asyncResp->res); 203784e12cb7SAppaRao Puli return; 203865b0dc32SEd Tanous } 2039002d39b4SEd Tanous asyncResp->res.jsonValue["Enabled"] = *userEnabled; 204065b0dc32SEd Tanous } 2041002d39b4SEd Tanous else if (property.first == "UserLockedForFailedAttempt") 204265b0dc32SEd Tanous { 204365b0dc32SEd Tanous const bool* userLocked = 2044abf2add6SEd Tanous std::get_if<bool>(&property.second); 204565b0dc32SEd Tanous if (userLocked == nullptr) 204665b0dc32SEd Tanous { 204762598e31SEd Tanous BMCWEB_LOG_ERROR("UserLockedForF" 204884e12cb7SAppaRao Puli "ailedAttempt " 204962598e31SEd Tanous "wasn't a bool"); 205084e12cb7SAppaRao Puli messages::internalError(asyncResp->res); 205184e12cb7SAppaRao Puli return; 205265b0dc32SEd Tanous } 2053002d39b4SEd Tanous asyncResp->res.jsonValue["Locked"] = *userLocked; 205420fa6a2cSEd Tanous nlohmann::json::array_t allowed; 205520fa6a2cSEd Tanous // can only unlock accounts 205620fa6a2cSEd Tanous allowed.emplace_back("false"); 2057002d39b4SEd Tanous asyncResp->res 205820fa6a2cSEd Tanous .jsonValue["Locked@Redfish.AllowableValues"] = 205920fa6a2cSEd Tanous std::move(allowed); 206065b0dc32SEd Tanous } 206184e12cb7SAppaRao Puli else if (property.first == "UserPrivilege") 206284e12cb7SAppaRao Puli { 206354fc587aSNagaraju Goruganti const std::string* userPrivPtr = 2064002d39b4SEd Tanous std::get_if<std::string>(&property.second); 206554fc587aSNagaraju Goruganti if (userPrivPtr == nullptr) 206684e12cb7SAppaRao Puli { 206762598e31SEd Tanous BMCWEB_LOG_ERROR("UserPrivilege wasn't a " 206862598e31SEd Tanous "string"); 206984e12cb7SAppaRao Puli messages::internalError(asyncResp->res); 207084e12cb7SAppaRao Puli return; 207184e12cb7SAppaRao Puli } 2072bd79bce8SPatrick Williams std::string role = 2073bd79bce8SPatrick Williams getRoleIdFromPrivilege(*userPrivPtr); 207454fc587aSNagaraju Goruganti if (role.empty()) 207584e12cb7SAppaRao Puli { 207662598e31SEd Tanous BMCWEB_LOG_ERROR("Invalid user role"); 207784e12cb7SAppaRao Puli messages::internalError(asyncResp->res); 207884e12cb7SAppaRao Puli return; 207984e12cb7SAppaRao Puli } 208054fc587aSNagaraju Goruganti asyncResp->res.jsonValue["RoleId"] = role; 208184e12cb7SAppaRao Puli 20821476687dSEd Tanous nlohmann::json& roleEntry = 2083002d39b4SEd Tanous asyncResp->res.jsonValue["Links"]["Role"]; 20843b32780dSEd Tanous roleEntry["@odata.id"] = boost::urls::format( 20853b32780dSEd Tanous "/redfish/v1/AccountService/Roles/{}", role); 208684e12cb7SAppaRao Puli } 2087002d39b4SEd Tanous else if (property.first == "UserPasswordExpired") 20883bf4e632SJoseph Reynolds { 20893bf4e632SJoseph Reynolds const bool* userPasswordExpired = 20903bf4e632SJoseph Reynolds std::get_if<bool>(&property.second); 20913bf4e632SJoseph Reynolds if (userPasswordExpired == nullptr) 20923bf4e632SJoseph Reynolds { 209362598e31SEd Tanous BMCWEB_LOG_ERROR( 209462598e31SEd Tanous "UserPasswordExpired wasn't a bool"); 20953bf4e632SJoseph Reynolds messages::internalError(asyncResp->res); 20963bf4e632SJoseph Reynolds return; 20973bf4e632SJoseph Reynolds } 2098002d39b4SEd Tanous asyncResp->res.jsonValue["PasswordChangeRequired"] = 20993bf4e632SJoseph Reynolds *userPasswordExpired; 21003bf4e632SJoseph Reynolds } 2101c7229815SAbhishek Patel else if (property.first == "UserGroups") 2102c7229815SAbhishek Patel { 2103c7229815SAbhishek Patel const std::vector<std::string>* userGroups = 2104c7229815SAbhishek Patel std::get_if<std::vector<std::string>>( 2105c7229815SAbhishek Patel &property.second); 2106c7229815SAbhishek Patel if (userGroups == nullptr) 2107c7229815SAbhishek Patel { 210862598e31SEd Tanous BMCWEB_LOG_ERROR( 210962598e31SEd Tanous "userGroups wasn't a string vector"); 2110c7229815SAbhishek Patel messages::internalError(asyncResp->res); 2111c7229815SAbhishek Patel return; 2112c7229815SAbhishek Patel } 2113bd79bce8SPatrick Williams if (!translateUserGroup(*userGroups, 2114bd79bce8SPatrick Williams asyncResp->res)) 2115c7229815SAbhishek Patel { 211662598e31SEd Tanous BMCWEB_LOG_ERROR("userGroups mapping failed"); 2117c7229815SAbhishek Patel messages::internalError(asyncResp->res); 2118c7229815SAbhishek Patel return; 2119c7229815SAbhishek Patel } 2120c7229815SAbhishek Patel } 212165b0dc32SEd Tanous } 212265b0dc32SEd Tanous } 212365b0dc32SEd Tanous } 212465b0dc32SEd Tanous 21253b32780dSEd Tanous asyncResp->res.jsonValue["@odata.id"] = boost::urls::format( 21263b32780dSEd Tanous "/redfish/v1/AccountService/Accounts/{}", accountName); 2127b9b2e0b2SEd Tanous asyncResp->res.jsonValue["Id"] = accountName; 2128b9b2e0b2SEd Tanous asyncResp->res.jsonValue["UserName"] = accountName; 21295eb468daSGeorge Liu }); 21301ef4c342SEd Tanous } 2131a840879dSEd Tanous 21321ef4c342SEd Tanous inline void 213320fc307fSGunnar Mills handleAccountDelete(App& app, const crow::Request& req, 21346c51eab1SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 21351ef4c342SEd Tanous const std::string& username) 21361ef4c342SEd Tanous { 21373ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 213845ca1b86SEd Tanous { 213945ca1b86SEd Tanous return; 214045ca1b86SEd Tanous } 21411ef4c342SEd Tanous 214225b54dbaSEd Tanous if constexpr (BMCWEB_INSECURE_DISABLE_AUTH) 214325b54dbaSEd Tanous { 2144031514fbSJunLin Chen // If authentication is disabled, there are no user accounts 2145d8a5d5d8SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "ManagerAccount", username); 2146031514fbSJunLin Chen return; 214725b54dbaSEd Tanous } 21481ef4c342SEd Tanous sdbusplus::message::object_path tempObjPath(rootUserDbusPath); 21491ef4c342SEd Tanous tempObjPath /= username; 21501ef4c342SEd Tanous const std::string userPath(tempObjPath); 21511ef4c342SEd Tanous 21521ef4c342SEd Tanous crow::connections::systemBus->async_method_call( 21535e7e2dc5SEd Tanous [asyncResp, username](const boost::system::error_code& ec) { 21541ef4c342SEd Tanous if (ec) 21551ef4c342SEd Tanous { 2156d8a5d5d8SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "ManagerAccount", 21571ef4c342SEd Tanous username); 21581ef4c342SEd Tanous return; 21591ef4c342SEd Tanous } 21601ef4c342SEd Tanous 21611ef4c342SEd Tanous messages::accountRemoved(asyncResp->res); 21621ef4c342SEd Tanous }, 21631ef4c342SEd Tanous "xyz.openbmc_project.User.Manager", userPath, 21641ef4c342SEd Tanous "xyz.openbmc_project.Object.Delete", "Delete"); 21651ef4c342SEd Tanous } 21661ef4c342SEd Tanous 21671ef4c342SEd Tanous inline void 21681ef4c342SEd Tanous handleAccountPatch(App& app, const crow::Request& req, 21691ef4c342SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 21701ef4c342SEd Tanous const std::string& username) 21711ef4c342SEd Tanous { 21721ef4c342SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 21731ef4c342SEd Tanous { 21741ef4c342SEd Tanous return; 21751ef4c342SEd Tanous } 217625b54dbaSEd Tanous if constexpr (BMCWEB_INSECURE_DISABLE_AUTH) 217725b54dbaSEd Tanous { 21781ef4c342SEd Tanous // If authentication is disabled, there are no user accounts 2179d8a5d5d8SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "ManagerAccount", username); 21801ef4c342SEd Tanous return; 218125b54dbaSEd Tanous } 2182a24526dcSEd Tanous std::optional<std::string> newUserName; 2183a24526dcSEd Tanous std::optional<std::string> password; 2184a24526dcSEd Tanous std::optional<bool> enabled; 2185a24526dcSEd Tanous std::optional<std::string> roleId; 218624c8542dSRatan Gupta std::optional<bool> locked; 218758345856SAbhishek Patel std::optional<std::vector<std::string>> accountTypes; 218858345856SAbhishek Patel 2189031514fbSJunLin Chen if (req.session == nullptr) 2190031514fbSJunLin Chen { 2191031514fbSJunLin Chen messages::internalError(asyncResp->res); 2192031514fbSJunLin Chen return; 2193031514fbSJunLin Chen } 2194031514fbSJunLin Chen 21952b9c1dfeSEd Tanous bool userSelf = (username == req.session->username); 21962b9c1dfeSEd Tanous 2197e9cc5172SEd Tanous Privileges effectiveUserPrivileges = 21983e72c202SNinad Palsule redfish::getUserPrivileges(*req.session); 2199e9cc5172SEd Tanous Privileges configureUsers = {"ConfigureUsers"}; 2200e9cc5172SEd Tanous bool userHasConfigureUsers = 2201e9cc5172SEd Tanous effectiveUserPrivileges.isSupersetOf(configureUsers); 2202e9cc5172SEd Tanous if (userHasConfigureUsers) 2203e9cc5172SEd Tanous { 2204e9cc5172SEd Tanous // Users with ConfigureUsers can modify for all users 220558345856SAbhishek Patel if (!json_util::readJsonPatch( 220658345856SAbhishek Patel req, asyncResp->res, "UserName", newUserName, "Password", 220758345856SAbhishek Patel password, "RoleId", roleId, "Enabled", enabled, "Locked", 220858345856SAbhishek Patel locked, "AccountTypes", accountTypes)) 2209a840879dSEd Tanous { 2210a840879dSEd Tanous return; 2211a840879dSEd Tanous } 2212e9cc5172SEd Tanous } 2213e9cc5172SEd Tanous else 2214900f9497SJoseph Reynolds { 2215e9cc5172SEd Tanous // ConfigureSelf accounts can only modify their own account 221658345856SAbhishek Patel if (!userSelf) 2217900f9497SJoseph Reynolds { 2218900f9497SJoseph Reynolds messages::insufficientPrivilege(asyncResp->res); 2219900f9497SJoseph Reynolds return; 2220900f9497SJoseph Reynolds } 2221031514fbSJunLin Chen 2222e9cc5172SEd Tanous // ConfigureSelf accounts can only modify their password 22231ef4c342SEd Tanous if (!json_util::readJsonPatch(req, asyncResp->res, "Password", 22241ef4c342SEd Tanous password)) 2225e9cc5172SEd Tanous { 2226e9cc5172SEd Tanous return; 2227e9cc5172SEd Tanous } 2228900f9497SJoseph Reynolds } 2229900f9497SJoseph Reynolds 223066b5ca76Sjayaprakash Mutyala // if user name is not provided in the patch method or if it 22316c51eab1SEd Tanous // matches the user name in the URI, then we are treating it as 22326c51eab1SEd Tanous // updating user properties other then username. If username 22336c51eab1SEd Tanous // provided doesn't match the URI, then we are treating this as 22346c51eab1SEd Tanous // user rename request. 223566b5ca76Sjayaprakash Mutyala if (!newUserName || (newUserName.value() == username)) 2236a840879dSEd Tanous { 22371ef4c342SEd Tanous updateUserProperties(asyncResp, username, password, enabled, roleId, 2238e518ef32SRavi Teja locked, accountTypes, userSelf, req.session); 223984e12cb7SAppaRao Puli return; 224084e12cb7SAppaRao Puli } 224184e12cb7SAppaRao Puli crow::connections::systemBus->async_method_call( 22426c51eab1SEd Tanous [asyncResp, username, password(std::move(password)), 22431ef4c342SEd Tanous roleId(std::move(roleId)), enabled, newUser{std::string(*newUserName)}, 2244e518ef32SRavi Teja locked, userSelf, req, accountTypes(std::move(accountTypes))]( 2245e81de512SEd Tanous const boost::system::error_code& ec, sdbusplus::message_t& m) { 224684e12cb7SAppaRao Puli if (ec) 224784e12cb7SAppaRao Puli { 2248002d39b4SEd Tanous userErrorMessageHandler(m.get_error(), asyncResp, newUser, 2249002d39b4SEd Tanous username); 2250a840879dSEd Tanous return; 2251a840879dSEd Tanous } 2252a840879dSEd Tanous 2253002d39b4SEd Tanous updateUserProperties(asyncResp, newUser, password, enabled, roleId, 2254e518ef32SRavi Teja locked, accountTypes, userSelf, req.session); 225584e12cb7SAppaRao Puli }, 22561ef4c342SEd Tanous "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user", 225784e12cb7SAppaRao Puli "xyz.openbmc_project.User.Manager", "RenameUser", username, 225884e12cb7SAppaRao Puli *newUserName); 22591ef4c342SEd Tanous } 22601ef4c342SEd Tanous 22611ef4c342SEd Tanous inline void requestAccountServiceRoutes(App& app) 22621ef4c342SEd Tanous { 22631ef4c342SEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/AccountService/") 22644c7d4d33SEd Tanous .privileges(redfish::privileges::headAccountService) 22654c7d4d33SEd Tanous .methods(boost::beast::http::verb::head)( 22664c7d4d33SEd Tanous std::bind_front(handleAccountServiceHead, std::ref(app))); 22674c7d4d33SEd Tanous 22684c7d4d33SEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/AccountService/") 22691ef4c342SEd Tanous .privileges(redfish::privileges::getAccountService) 22701ef4c342SEd Tanous .methods(boost::beast::http::verb::get)( 22711ef4c342SEd Tanous std::bind_front(handleAccountServiceGet, std::ref(app))); 22721ef4c342SEd Tanous 22731ef4c342SEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/AccountService/") 22741ef4c342SEd Tanous .privileges(redfish::privileges::patchAccountService) 22751ef4c342SEd Tanous .methods(boost::beast::http::verb::patch)( 22761ef4c342SEd Tanous std::bind_front(handleAccountServicePatch, std::ref(app))); 22771ef4c342SEd Tanous 22781aa375b8SEd Tanous BMCWEB_ROUTE( 22791aa375b8SEd Tanous app, 2280*e9f12014SEd Tanous "/redfish/v1/AccountService/MultiFactorAuth/ClientCertificate/Certificates/") 22811aa375b8SEd Tanous .privileges(redfish::privileges::headCertificateCollection) 22821aa375b8SEd Tanous .methods(boost::beast::http::verb::head)(std::bind_front( 22831aa375b8SEd Tanous handleAccountServiceClientCertificatesHead, std::ref(app))); 22841aa375b8SEd Tanous 22851aa375b8SEd Tanous BMCWEB_ROUTE( 22861aa375b8SEd Tanous app, 2287*e9f12014SEd Tanous "/redfish/v1/AccountService/MultiFactorAuth/ClientCertificate/Certificates/") 22881aa375b8SEd Tanous .privileges(redfish::privileges::getCertificateCollection) 22891aa375b8SEd Tanous .methods(boost::beast::http::verb::get)(std::bind_front( 22901aa375b8SEd Tanous handleAccountServiceClientCertificatesGet, std::ref(app))); 22911aa375b8SEd Tanous 22921aa375b8SEd Tanous BMCWEB_ROUTE( 22931aa375b8SEd Tanous app, 2294*e9f12014SEd Tanous "/redfish/v1/AccountService/MultiFactorAuth/ClientCertificate/Certificates/<str>/") 22951aa375b8SEd Tanous .privileges(redfish::privileges::headCertificate) 22961aa375b8SEd Tanous .methods(boost::beast::http::verb::head)(std::bind_front( 22971aa375b8SEd Tanous handleAccountServiceClientCertificatesInstanceHead, std::ref(app))); 22981aa375b8SEd Tanous 22991aa375b8SEd Tanous BMCWEB_ROUTE( 23001aa375b8SEd Tanous app, 23011aa375b8SEd Tanous "/redfish/v1/AccountService/MultiFactorAuth/ClientCertificate/Certificates/<str>/") 23021aa375b8SEd Tanous .privileges(redfish::privileges::getCertificate) 23031aa375b8SEd Tanous .methods(boost::beast::http::verb::get)(std::bind_front( 23041aa375b8SEd Tanous handleAccountServiceClientCertificatesInstanceGet, std::ref(app))); 23051aa375b8SEd Tanous 23061ef4c342SEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/") 23074c7d4d33SEd Tanous .privileges(redfish::privileges::headManagerAccountCollection) 23084c7d4d33SEd Tanous .methods(boost::beast::http::verb::head)( 23094c7d4d33SEd Tanous std::bind_front(handleAccountCollectionHead, std::ref(app))); 23104c7d4d33SEd Tanous 23114c7d4d33SEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/") 23121ef4c342SEd Tanous .privileges(redfish::privileges::getManagerAccountCollection) 23131ef4c342SEd Tanous .methods(boost::beast::http::verb::get)( 23141ef4c342SEd Tanous std::bind_front(handleAccountCollectionGet, std::ref(app))); 23151ef4c342SEd Tanous 23161ef4c342SEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/") 23171ef4c342SEd Tanous .privileges(redfish::privileges::postManagerAccountCollection) 23181ef4c342SEd Tanous .methods(boost::beast::http::verb::post)( 23191ef4c342SEd Tanous std::bind_front(handleAccountCollectionPost, std::ref(app))); 23201ef4c342SEd Tanous 23211ef4c342SEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/<str>/") 23224c7d4d33SEd Tanous .privileges(redfish::privileges::headManagerAccount) 23234c7d4d33SEd Tanous .methods(boost::beast::http::verb::head)( 23244c7d4d33SEd Tanous std::bind_front(handleAccountHead, std::ref(app))); 23254c7d4d33SEd Tanous 23264c7d4d33SEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/<str>/") 23271ef4c342SEd Tanous .privileges(redfish::privileges::getManagerAccount) 23281ef4c342SEd Tanous .methods(boost::beast::http::verb::get)( 23291ef4c342SEd Tanous std::bind_front(handleAccountGet, std::ref(app))); 23301ef4c342SEd Tanous 23311ef4c342SEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/<str>/") 23321ef4c342SEd Tanous // TODO this privilege should be using the generated endpoints, but 23331ef4c342SEd Tanous // because of the special handling of ConfigureSelf, it's not able to 23341ef4c342SEd Tanous // yet 23351ef4c342SEd Tanous .privileges({{"ConfigureUsers"}, {"ConfigureSelf"}}) 23361ef4c342SEd Tanous .methods(boost::beast::http::verb::patch)( 23371ef4c342SEd Tanous std::bind_front(handleAccountPatch, std::ref(app))); 233884e12cb7SAppaRao Puli 23396c51eab1SEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/<str>/") 2340ed398213SEd Tanous .privileges(redfish::privileges::deleteManagerAccount) 23416c51eab1SEd Tanous .methods(boost::beast::http::verb::delete_)( 234220fc307fSGunnar Mills std::bind_front(handleAccountDelete, std::ref(app))); 234306e086d9SEd Tanous } 234488d16c9aSLewanczyk, Dawid 234588d16c9aSLewanczyk, Dawid } // namespace redfish 2346