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 420*afc474aeSMyung Bae if (!json_util::readJsonObject( // 421*afc474aeSMyung Bae *obj, asyncResp->res, // 422*afc474aeSMyung Bae "LocalRole", localRole, // 423*afc474aeSMyung Bae "RemoteGroup", remoteGroup // 424*afc474aeSMyung Bae )) 42506785244SRatan Gupta { 42606785244SRatan Gupta continue; 42706785244SRatan Gupta } 42806785244SRatan Gupta 42906785244SRatan Gupta // Update existing RoleMapping Object 43006785244SRatan Gupta if (index < roleMapObjData.size()) 43106785244SRatan Gupta { 43262598e31SEd Tanous BMCWEB_LOG_DEBUG("Update Role Map Object"); 43306785244SRatan Gupta // If "RemoteGroup" info is provided 43406785244SRatan Gupta if (remoteGroup) 43506785244SRatan Gupta { 436d02aad39SEd Tanous setDbusProperty( 437e93abac6SGinu George asyncResp, 438d02aad39SEd Tanous std::format("RemoteRoleMapping/{}/RemoteGroup", index), 439e93abac6SGinu George ldapDbusService, roleMapObjData[index].first, 440e93abac6SGinu George "xyz.openbmc_project.User.PrivilegeMapperEntry", 441e93abac6SGinu George "GroupName", *remoteGroup); 44206785244SRatan Gupta } 44306785244SRatan Gupta 44406785244SRatan Gupta // If "LocalRole" info is provided 44506785244SRatan Gupta if (localRole) 44606785244SRatan Gupta { 4476d0b80beSRavi Teja std::string priv = getPrivilegeFromRoleId(*localRole); 4486d0b80beSRavi Teja if (priv.empty()) 4496d0b80beSRavi Teja { 4506d0b80beSRavi Teja messages::propertyValueNotInList( 4516d0b80beSRavi Teja asyncResp->res, *localRole, 4526d0b80beSRavi Teja std::format("RemoteRoleMapping/{}/LocalRole", 4536d0b80beSRavi Teja index)); 4546d0b80beSRavi Teja return; 4556d0b80beSRavi Teja } 456d02aad39SEd Tanous setDbusProperty( 457e93abac6SGinu George asyncResp, 458d02aad39SEd Tanous std::format("RemoteRoleMapping/{}/LocalRole", index), 459e93abac6SGinu George ldapDbusService, roleMapObjData[index].first, 460e93abac6SGinu George "xyz.openbmc_project.User.PrivilegeMapperEntry", 4616d0b80beSRavi Teja "Privilege", priv); 46206785244SRatan Gupta } 46306785244SRatan Gupta } 46406785244SRatan Gupta // Create a new RoleMapping Object. 46506785244SRatan Gupta else 46606785244SRatan Gupta { 46762598e31SEd Tanous BMCWEB_LOG_DEBUG( 46862598e31SEd Tanous "setRoleMappingProperties: Creating new Object"); 469bd79bce8SPatrick Williams std::string pathString = 470bd79bce8SPatrick Williams "RemoteRoleMapping/" + std::to_string(index); 47106785244SRatan Gupta 47206785244SRatan Gupta if (!localRole) 47306785244SRatan Gupta { 47406785244SRatan Gupta messages::propertyMissing(asyncResp->res, 47506785244SRatan Gupta pathString + "/LocalRole"); 47606785244SRatan Gupta continue; 47706785244SRatan Gupta } 47806785244SRatan Gupta if (!remoteGroup) 47906785244SRatan Gupta { 48006785244SRatan Gupta messages::propertyMissing(asyncResp->res, 48106785244SRatan Gupta pathString + "/RemoteGroup"); 48206785244SRatan Gupta continue; 48306785244SRatan Gupta } 48406785244SRatan Gupta 48506785244SRatan Gupta std::string dbusObjectPath; 48606785244SRatan Gupta if (serverType == "ActiveDirectory") 48706785244SRatan Gupta { 4882c70f800SEd Tanous dbusObjectPath = adConfigObject; 48906785244SRatan Gupta } 49006785244SRatan Gupta else if (serverType == "LDAP") 49106785244SRatan Gupta { 49223a21a1cSEd Tanous dbusObjectPath = ldapConfigObjectName; 49306785244SRatan Gupta } 49406785244SRatan Gupta 49562598e31SEd Tanous BMCWEB_LOG_DEBUG("Remote Group={},LocalRole={}", *remoteGroup, 49662598e31SEd Tanous *localRole); 49706785244SRatan Gupta 49806785244SRatan Gupta crow::connections::systemBus->async_method_call( 499271584abSEd Tanous [asyncResp, serverType, localRole, 5005e7e2dc5SEd Tanous remoteGroup](const boost::system::error_code& ec) { 50106785244SRatan Gupta if (ec) 50206785244SRatan Gupta { 50362598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error: {}", ec); 50406785244SRatan Gupta messages::internalError(asyncResp->res); 50506785244SRatan Gupta return; 50606785244SRatan Gupta } 50706785244SRatan Gupta nlohmann::json& remoteRoleJson = 50806785244SRatan Gupta asyncResp->res 50906785244SRatan Gupta .jsonValue[serverType]["RemoteRoleMapping"]; 5101476687dSEd Tanous nlohmann::json::object_t roleMapEntry; 5111476687dSEd Tanous roleMapEntry["LocalRole"] = *localRole; 5121476687dSEd Tanous roleMapEntry["RemoteGroup"] = *remoteGroup; 513b2ba3072SPatrick Williams remoteRoleJson.emplace_back(std::move(roleMapEntry)); 51406785244SRatan Gupta }, 51506785244SRatan Gupta ldapDbusService, dbusObjectPath, ldapPrivMapperInterface, 5163174e4dfSEd Tanous "Create", *remoteGroup, 51706785244SRatan Gupta getPrivilegeFromRoleId(std::move(*localRole))); 51806785244SRatan Gupta } 51906785244SRatan Gupta } 52006785244SRatan Gupta } 52106785244SRatan Gupta } 52206785244SRatan Gupta 52306785244SRatan Gupta /** 5246973a582SRatan Gupta * Function that retrieves all properties for LDAP config object 5256973a582SRatan Gupta * into JSON 5266973a582SRatan Gupta */ 5276973a582SRatan Gupta template <typename CallbackFunc> 528bd79bce8SPatrick Williams inline void 529bd79bce8SPatrick Williams getLDAPConfigData(const std::string& ldapType, CallbackFunc&& callback) 5306973a582SRatan Gupta { 5312b73119cSGeorge Liu constexpr std::array<std::string_view, 2> interfaces = { 5322b73119cSGeorge Liu ldapEnableInterface, ldapConfigInterface}; 53354fc587aSNagaraju Goruganti 5342b73119cSGeorge Liu dbus::utility::getDbusObject( 5352b73119cSGeorge Liu ldapConfigObjectName, interfaces, 5368cb2c024SEd Tanous [callback = std::forward<CallbackFunc>(callback), 537c1019828SEd Tanous ldapType](const boost::system::error_code& ec, 538c1019828SEd Tanous const dbus::utility::MapperGetObject& resp) mutable { 53954fc587aSNagaraju Goruganti if (ec || resp.empty()) 54054fc587aSNagaraju Goruganti { 541bf2ddedeSCarson Labrado BMCWEB_LOG_WARNING( 542bd79bce8SPatrick Williams "DBUS response error during getting of service name: {}", 543bd79bce8SPatrick Williams ec); 54423a21a1cSEd Tanous LDAPConfigData empty{}; 54523a21a1cSEd Tanous callback(false, empty, ldapType); 54654fc587aSNagaraju Goruganti return; 54754fc587aSNagaraju Goruganti } 54854fc587aSNagaraju Goruganti std::string service = resp.begin()->first; 5495eb468daSGeorge Liu sdbusplus::message::object_path path(ldapRootObject); 5505eb468daSGeorge Liu dbus::utility::getManagedObjects( 5515eb468daSGeorge Liu service, path, 552bd79bce8SPatrick Williams [callback, ldapType](const boost::system::error_code& ec2, 553bd79bce8SPatrick Williams const dbus::utility::ManagedObjectType& 554bd79bce8SPatrick Williams ldapObjects) mutable { 5556973a582SRatan Gupta LDAPConfigData confData{}; 5568b24275dSEd Tanous if (ec2) 5576973a582SRatan Gupta { 558ab828d7cSRatan Gupta callback(false, confData, ldapType); 559bf2ddedeSCarson Labrado BMCWEB_LOG_WARNING("D-Bus responses error: {}", ec2); 5606973a582SRatan Gupta return; 5616973a582SRatan Gupta } 562ab828d7cSRatan Gupta 563ab828d7cSRatan Gupta std::string ldapDbusType; 56454fc587aSNagaraju Goruganti std::string searchString; 56554fc587aSNagaraju Goruganti 566ab828d7cSRatan Gupta if (ldapType == "LDAP") 567ab828d7cSRatan Gupta { 5680fda0f12SGeorge Liu ldapDbusType = 5690fda0f12SGeorge Liu "xyz.openbmc_project.User.Ldap.Config.Type.OpenLdap"; 57054fc587aSNagaraju Goruganti searchString = "openldap"; 571ab828d7cSRatan Gupta } 572ab828d7cSRatan Gupta else if (ldapType == "ActiveDirectory") 573ab828d7cSRatan Gupta { 57454fc587aSNagaraju Goruganti ldapDbusType = 5750fda0f12SGeorge Liu "xyz.openbmc_project.User.Ldap.Config.Type.ActiveDirectory"; 57654fc587aSNagaraju Goruganti searchString = "active_directory"; 577ab828d7cSRatan Gupta } 578ab828d7cSRatan Gupta else 579ab828d7cSRatan Gupta { 580bd79bce8SPatrick Williams BMCWEB_LOG_ERROR( 581bd79bce8SPatrick Williams "Can't get the DbusType for the given type={}", 58262598e31SEd Tanous ldapType); 583ab828d7cSRatan Gupta callback(false, confData, ldapType); 584ab828d7cSRatan Gupta return; 585ab828d7cSRatan Gupta } 586ab828d7cSRatan Gupta 587ab828d7cSRatan Gupta std::string ldapEnableInterfaceStr = ldapEnableInterface; 588ab828d7cSRatan Gupta std::string ldapConfigInterfaceStr = ldapConfigInterface; 589ab828d7cSRatan Gupta 5906973a582SRatan Gupta for (const auto& object : ldapObjects) 5916973a582SRatan Gupta { 59254fc587aSNagaraju Goruganti // let's find the object whose ldap type is equal to the 59354fc587aSNagaraju Goruganti // given type 594bd79bce8SPatrick Williams if (object.first.str.find(searchString) == 595bd79bce8SPatrick Williams std::string::npos) 5966973a582SRatan Gupta { 597ab828d7cSRatan Gupta continue; 598ab828d7cSRatan Gupta } 599ab828d7cSRatan Gupta 6006973a582SRatan Gupta for (const auto& interface : object.second) 6016973a582SRatan Gupta { 6026973a582SRatan Gupta if (interface.first == ldapEnableInterfaceStr) 6036973a582SRatan Gupta { 6046973a582SRatan Gupta // rest of the properties are string. 6056973a582SRatan Gupta for (const auto& property : interface.second) 6066973a582SRatan Gupta { 6076973a582SRatan Gupta if (property.first == "Enabled") 6086973a582SRatan Gupta { 6096973a582SRatan Gupta const bool* value = 6106973a582SRatan Gupta std::get_if<bool>(&property.second); 6116973a582SRatan Gupta if (value == nullptr) 6126973a582SRatan Gupta { 6136973a582SRatan Gupta continue; 6146973a582SRatan Gupta } 6156973a582SRatan Gupta confData.serviceEnabled = *value; 6166973a582SRatan Gupta break; 6176973a582SRatan Gupta } 6186973a582SRatan Gupta } 6196973a582SRatan Gupta } 6206973a582SRatan Gupta else if (interface.first == ldapConfigInterfaceStr) 6216973a582SRatan Gupta { 6226973a582SRatan Gupta for (const auto& property : interface.second) 6236973a582SRatan Gupta { 624271584abSEd Tanous const std::string* strValue = 625bd79bce8SPatrick Williams std::get_if<std::string>( 626bd79bce8SPatrick Williams &property.second); 627271584abSEd Tanous if (strValue == nullptr) 6286973a582SRatan Gupta { 6296973a582SRatan Gupta continue; 6306973a582SRatan Gupta } 6316973a582SRatan Gupta if (property.first == "LDAPServerURI") 6326973a582SRatan Gupta { 633271584abSEd Tanous confData.uri = *strValue; 6346973a582SRatan Gupta } 6356973a582SRatan Gupta else if (property.first == "LDAPBindDN") 6366973a582SRatan Gupta { 637271584abSEd Tanous confData.bindDN = *strValue; 6386973a582SRatan Gupta } 6396973a582SRatan Gupta else if (property.first == "LDAPBaseDN") 6406973a582SRatan Gupta { 641271584abSEd Tanous confData.baseDN = *strValue; 6426973a582SRatan Gupta } 643bd79bce8SPatrick Williams else if (property.first == 644bd79bce8SPatrick Williams "LDAPSearchScope") 6456973a582SRatan Gupta { 646271584abSEd Tanous confData.searchScope = *strValue; 6476973a582SRatan Gupta } 648bd79bce8SPatrick Williams else if (property.first == 649bd79bce8SPatrick Williams "GroupNameAttribute") 6506973a582SRatan Gupta { 651271584abSEd Tanous confData.groupAttribute = *strValue; 6526973a582SRatan Gupta } 653bd79bce8SPatrick Williams else if (property.first == 654bd79bce8SPatrick Williams "UserNameAttribute") 6556973a582SRatan Gupta { 656271584abSEd Tanous confData.userNameAttribute = *strValue; 6576973a582SRatan Gupta } 65854fc587aSNagaraju Goruganti else if (property.first == "LDAPType") 659ab828d7cSRatan Gupta { 660271584abSEd Tanous confData.serverType = *strValue; 66154fc587aSNagaraju Goruganti } 66254fc587aSNagaraju Goruganti } 66354fc587aSNagaraju Goruganti } 664bd79bce8SPatrick Williams else if ( 665bd79bce8SPatrick Williams interface.first == 6660fda0f12SGeorge Liu "xyz.openbmc_project.User.PrivilegeMapperEntry") 66754fc587aSNagaraju Goruganti { 66854fc587aSNagaraju Goruganti LDAPRoleMapData roleMapData{}; 66954fc587aSNagaraju Goruganti for (const auto& property : interface.second) 67054fc587aSNagaraju Goruganti { 671271584abSEd Tanous const std::string* strValue = 672bd79bce8SPatrick Williams std::get_if<std::string>( 673bd79bce8SPatrick Williams &property.second); 67454fc587aSNagaraju Goruganti 675271584abSEd Tanous if (strValue == nullptr) 67654fc587aSNagaraju Goruganti { 67754fc587aSNagaraju Goruganti continue; 67854fc587aSNagaraju Goruganti } 67954fc587aSNagaraju Goruganti 68054fc587aSNagaraju Goruganti if (property.first == "GroupName") 68154fc587aSNagaraju Goruganti { 682271584abSEd Tanous roleMapData.groupName = *strValue; 68354fc587aSNagaraju Goruganti } 68454fc587aSNagaraju Goruganti else if (property.first == "Privilege") 68554fc587aSNagaraju Goruganti { 686271584abSEd Tanous roleMapData.privilege = *strValue; 68754fc587aSNagaraju Goruganti } 68854fc587aSNagaraju Goruganti } 68954fc587aSNagaraju Goruganti 690bd79bce8SPatrick Williams confData.groupRoleList.emplace_back( 691bd79bce8SPatrick Williams object.first.str, roleMapData); 69254fc587aSNagaraju Goruganti } 69354fc587aSNagaraju Goruganti } 69454fc587aSNagaraju Goruganti } 695ab828d7cSRatan Gupta callback(true, confData, ldapType); 6965eb468daSGeorge Liu }); 6972b73119cSGeorge Liu }); 6986973a582SRatan Gupta } 6996973a582SRatan Gupta 7008a07d286SRatan Gupta /** 7018a07d286SRatan Gupta * @brief updates the LDAP server address and updates the 7028a07d286SRatan Gupta json response with the new value. 7038a07d286SRatan Gupta * @param serviceAddressList address to be updated. 7048a07d286SRatan Gupta * @param asyncResp pointer to the JSON response 7058a07d286SRatan Gupta * @param ldapServerElementName Type of LDAP 7068a07d286SRatan Gupta server(openLDAP/ActiveDirectory) 7078a07d286SRatan Gupta */ 7088a07d286SRatan Gupta 7094f48d5f6SEd Tanous inline void handleServiceAddressPatch( 7108a07d286SRatan Gupta const std::vector<std::string>& serviceAddressList, 7118d1b46d7Szhanghch05 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 7128a07d286SRatan Gupta const std::string& ldapServerElementName, 7138a07d286SRatan Gupta const std::string& ldapConfigObject) 7148a07d286SRatan Gupta { 715e93abac6SGinu George setDbusProperty(asyncResp, ldapServerElementName + "/ServiceAddress", 716e93abac6SGinu George ldapDbusService, ldapConfigObject, ldapConfigInterface, 717e93abac6SGinu George "LDAPServerURI", serviceAddressList.front()); 7188a07d286SRatan Gupta } 7198a07d286SRatan Gupta /** 7208a07d286SRatan Gupta * @brief updates the LDAP Bind DN and updates the 7218a07d286SRatan Gupta json response with the new value. 7228a07d286SRatan Gupta * @param username name of the user which needs to be updated. 7238a07d286SRatan Gupta * @param asyncResp pointer to the JSON response 7248a07d286SRatan Gupta * @param ldapServerElementName Type of LDAP 7258a07d286SRatan Gupta server(openLDAP/ActiveDirectory) 7268a07d286SRatan Gupta */ 7278a07d286SRatan Gupta 7284f48d5f6SEd Tanous inline void 7294f48d5f6SEd Tanous handleUserNamePatch(const std::string& username, 7308d1b46d7Szhanghch05 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 7318a07d286SRatan Gupta const std::string& ldapServerElementName, 7328a07d286SRatan Gupta const std::string& ldapConfigObject) 7338a07d286SRatan Gupta { 734e93abac6SGinu George setDbusProperty(asyncResp, 735d02aad39SEd Tanous ldapServerElementName + "/Authentication/Username", 736e93abac6SGinu George ldapDbusService, ldapConfigObject, ldapConfigInterface, 737e93abac6SGinu George "LDAPBindDN", username); 7388a07d286SRatan Gupta } 7398a07d286SRatan Gupta 7408a07d286SRatan Gupta /** 7418a07d286SRatan Gupta * @brief updates the LDAP password 7428a07d286SRatan Gupta * @param password : ldap password which needs to be updated. 7438a07d286SRatan Gupta * @param asyncResp pointer to the JSON response 7448a07d286SRatan Gupta * @param ldapServerElementName Type of LDAP 7458a07d286SRatan Gupta * server(openLDAP/ActiveDirectory) 7468a07d286SRatan Gupta */ 7478a07d286SRatan Gupta 7484f48d5f6SEd Tanous inline void 7494f48d5f6SEd Tanous handlePasswordPatch(const std::string& password, 7508d1b46d7Szhanghch05 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 7518a07d286SRatan Gupta const std::string& ldapServerElementName, 7528a07d286SRatan Gupta const std::string& ldapConfigObject) 7538a07d286SRatan Gupta { 754e93abac6SGinu George setDbusProperty(asyncResp, 755d02aad39SEd Tanous ldapServerElementName + "/Authentication/Password", 756e93abac6SGinu George ldapDbusService, ldapConfigObject, ldapConfigInterface, 757e93abac6SGinu George "LDAPBindDNPassword", password); 7588a07d286SRatan Gupta } 7598a07d286SRatan Gupta 7608a07d286SRatan Gupta /** 7618a07d286SRatan Gupta * @brief updates the LDAP BaseDN and updates the 7628a07d286SRatan Gupta json response with the new value. 7638a07d286SRatan Gupta * @param baseDNList baseDN list which needs to be updated. 7648a07d286SRatan Gupta * @param asyncResp pointer to the JSON response 7658a07d286SRatan Gupta * @param ldapServerElementName Type of LDAP 7668a07d286SRatan Gupta server(openLDAP/ActiveDirectory) 7678a07d286SRatan Gupta */ 7688a07d286SRatan Gupta 7694f48d5f6SEd Tanous inline void 7704f48d5f6SEd Tanous handleBaseDNPatch(const std::vector<std::string>& baseDNList, 7718d1b46d7Szhanghch05 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 7728a07d286SRatan Gupta const std::string& ldapServerElementName, 7738a07d286SRatan Gupta const std::string& ldapConfigObject) 7748a07d286SRatan Gupta { 775e93abac6SGinu George setDbusProperty(asyncResp, 776d02aad39SEd Tanous ldapServerElementName + 777d02aad39SEd Tanous "/LDAPService/SearchSettings/BaseDistinguishedNames", 778e93abac6SGinu George ldapDbusService, ldapConfigObject, ldapConfigInterface, 779e93abac6SGinu George "LDAPBaseDN", baseDNList.front()); 7808a07d286SRatan Gupta } 7818a07d286SRatan Gupta /** 7828a07d286SRatan Gupta * @brief updates the LDAP user name attribute and updates the 7838a07d286SRatan Gupta json response with the new value. 7848a07d286SRatan Gupta * @param userNameAttribute attribute to be updated. 7858a07d286SRatan Gupta * @param asyncResp pointer to the JSON response 7868a07d286SRatan Gupta * @param ldapServerElementName Type of LDAP 7878a07d286SRatan Gupta server(openLDAP/ActiveDirectory) 7888a07d286SRatan Gupta */ 7898a07d286SRatan Gupta 790bd79bce8SPatrick Williams inline void handleUserNameAttrPatch( 791bd79bce8SPatrick Williams const std::string& userNameAttribute, 7928d1b46d7Szhanghch05 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 7938a07d286SRatan Gupta const std::string& ldapServerElementName, 7948a07d286SRatan Gupta const std::string& ldapConfigObject) 7958a07d286SRatan Gupta { 796bd79bce8SPatrick Williams setDbusProperty( 797bd79bce8SPatrick Williams asyncResp, 798bd79bce8SPatrick Williams ldapServerElementName + "LDAPService/SearchSettings/UsernameAttribute", 799e93abac6SGinu George ldapDbusService, ldapConfigObject, ldapConfigInterface, 800e93abac6SGinu George "UserNameAttribute", userNameAttribute); 8018a07d286SRatan Gupta } 8028a07d286SRatan Gupta /** 8038a07d286SRatan Gupta * @brief updates the LDAP group attribute and updates the 8048a07d286SRatan Gupta json response with the new value. 8058a07d286SRatan Gupta * @param groupsAttribute attribute to be updated. 8068a07d286SRatan Gupta * @param asyncResp pointer to the JSON response 8078a07d286SRatan Gupta * @param ldapServerElementName Type of LDAP 8088a07d286SRatan Gupta server(openLDAP/ActiveDirectory) 8098a07d286SRatan Gupta */ 8108a07d286SRatan Gupta 8114f48d5f6SEd Tanous inline void handleGroupNameAttrPatch( 8128d1b46d7Szhanghch05 const std::string& groupsAttribute, 8138d1b46d7Szhanghch05 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 8148a07d286SRatan Gupta const std::string& ldapServerElementName, 8158a07d286SRatan Gupta const std::string& ldapConfigObject) 8168a07d286SRatan Gupta { 817bd79bce8SPatrick Williams setDbusProperty( 818bd79bce8SPatrick Williams asyncResp, 819bd79bce8SPatrick Williams ldapServerElementName + "/LDAPService/SearchSettings/GroupsAttribute", 820e93abac6SGinu George ldapDbusService, ldapConfigObject, ldapConfigInterface, 821e93abac6SGinu George "GroupNameAttribute", groupsAttribute); 8228a07d286SRatan Gupta } 8238a07d286SRatan Gupta /** 8248a07d286SRatan Gupta * @brief updates the LDAP service enable and updates the 8258a07d286SRatan Gupta json response with the new value. 8268a07d286SRatan Gupta * @param input JSON data. 8278a07d286SRatan Gupta * @param asyncResp pointer to the JSON response 8288a07d286SRatan Gupta * @param ldapServerElementName Type of LDAP 8298a07d286SRatan Gupta server(openLDAP/ActiveDirectory) 8308a07d286SRatan Gupta */ 8318a07d286SRatan Gupta 8324f48d5f6SEd Tanous inline void handleServiceEnablePatch( 8336c51eab1SEd Tanous bool serviceEnabled, const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 8348a07d286SRatan Gupta const std::string& ldapServerElementName, 8358a07d286SRatan Gupta const std::string& ldapConfigObject) 8368a07d286SRatan Gupta { 837e93abac6SGinu George setDbusProperty(asyncResp, ldapServerElementName + "/ServiceEnabled", 838e93abac6SGinu George ldapDbusService, ldapConfigObject, ldapEnableInterface, 839e93abac6SGinu George "Enabled", serviceEnabled); 8408a07d286SRatan Gupta } 8418a07d286SRatan Gupta 842c1019828SEd Tanous struct AuthMethods 84378158631SZbigniew Kurzynski { 84478158631SZbigniew Kurzynski std::optional<bool> basicAuth; 84578158631SZbigniew Kurzynski std::optional<bool> cookie; 84678158631SZbigniew Kurzynski std::optional<bool> sessionToken; 84778158631SZbigniew Kurzynski std::optional<bool> xToken; 848501f1e58SZbigniew Kurzynski std::optional<bool> tls; 849c1019828SEd Tanous }; 85078158631SZbigniew Kurzynski 851c1019828SEd Tanous inline void 852c1019828SEd Tanous handleAuthMethodsPatch(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 853c1019828SEd Tanous const AuthMethods& auth) 85478158631SZbigniew Kurzynski { 855c1019828SEd Tanous persistent_data::AuthConfigMethods& authMethodsConfig = 85652cc112dSEd Tanous persistent_data::SessionStore::getInstance().getAuthMethodsConfig(); 85778158631SZbigniew Kurzynski 858c1019828SEd Tanous if (auth.basicAuth) 85978158631SZbigniew Kurzynski { 86025b54dbaSEd Tanous if constexpr (!BMCWEB_BASIC_AUTH) 86125b54dbaSEd Tanous { 862f16f6263SAlan Kuo messages::actionNotSupported( 8630fda0f12SGeorge Liu asyncResp->res, 8640fda0f12SGeorge Liu "Setting BasicAuth when basic-auth feature is disabled"); 865f16f6263SAlan Kuo return; 86625b54dbaSEd Tanous } 86725b54dbaSEd Tanous 868c1019828SEd Tanous authMethodsConfig.basic = *auth.basicAuth; 86978158631SZbigniew Kurzynski } 87078158631SZbigniew Kurzynski 871c1019828SEd Tanous if (auth.cookie) 87278158631SZbigniew Kurzynski { 87325b54dbaSEd Tanous if constexpr (!BMCWEB_COOKIE_AUTH) 87425b54dbaSEd Tanous { 8750fda0f12SGeorge Liu messages::actionNotSupported( 8760fda0f12SGeorge Liu asyncResp->res, 8770fda0f12SGeorge Liu "Setting Cookie when cookie-auth feature is disabled"); 878f16f6263SAlan Kuo return; 87925b54dbaSEd Tanous } 880c1019828SEd Tanous authMethodsConfig.cookie = *auth.cookie; 88178158631SZbigniew Kurzynski } 88278158631SZbigniew Kurzynski 883c1019828SEd Tanous if (auth.sessionToken) 88478158631SZbigniew Kurzynski { 88525b54dbaSEd Tanous if constexpr (!BMCWEB_SESSION_AUTH) 88625b54dbaSEd Tanous { 887f16f6263SAlan Kuo messages::actionNotSupported( 8880fda0f12SGeorge Liu asyncResp->res, 8890fda0f12SGeorge Liu "Setting SessionToken when session-auth feature is disabled"); 890f16f6263SAlan Kuo return; 89125b54dbaSEd Tanous } 892c1019828SEd Tanous authMethodsConfig.sessionToken = *auth.sessionToken; 89378158631SZbigniew Kurzynski } 89478158631SZbigniew Kurzynski 895c1019828SEd Tanous if (auth.xToken) 89678158631SZbigniew Kurzynski { 89725b54dbaSEd Tanous if constexpr (!BMCWEB_XTOKEN_AUTH) 89825b54dbaSEd Tanous { 8990fda0f12SGeorge Liu messages::actionNotSupported( 9000fda0f12SGeorge Liu asyncResp->res, 9010fda0f12SGeorge Liu "Setting XToken when xtoken-auth feature is disabled"); 902f16f6263SAlan Kuo return; 90325b54dbaSEd Tanous } 904c1019828SEd Tanous authMethodsConfig.xtoken = *auth.xToken; 90578158631SZbigniew Kurzynski } 90678158631SZbigniew Kurzynski 907c1019828SEd Tanous if (auth.tls) 908501f1e58SZbigniew Kurzynski { 90925b54dbaSEd Tanous if constexpr (!BMCWEB_MUTUAL_TLS_AUTH) 91025b54dbaSEd Tanous { 9110fda0f12SGeorge Liu messages::actionNotSupported( 9120fda0f12SGeorge Liu asyncResp->res, 9130fda0f12SGeorge Liu "Setting TLS when mutual-tls-auth feature is disabled"); 914f16f6263SAlan Kuo return; 91525b54dbaSEd Tanous } 916c1019828SEd Tanous authMethodsConfig.tls = *auth.tls; 917501f1e58SZbigniew Kurzynski } 918501f1e58SZbigniew Kurzynski 91978158631SZbigniew Kurzynski if (!authMethodsConfig.basic && !authMethodsConfig.cookie && 920501f1e58SZbigniew Kurzynski !authMethodsConfig.sessionToken && !authMethodsConfig.xtoken && 921501f1e58SZbigniew Kurzynski !authMethodsConfig.tls) 92278158631SZbigniew Kurzynski { 92378158631SZbigniew Kurzynski // Do not allow user to disable everything 92478158631SZbigniew Kurzynski messages::actionNotSupported(asyncResp->res, 92578158631SZbigniew Kurzynski "of disabling all available methods"); 92678158631SZbigniew Kurzynski return; 92778158631SZbigniew Kurzynski } 92878158631SZbigniew Kurzynski 92952cc112dSEd Tanous persistent_data::SessionStore::getInstance().updateAuthMethodsConfig( 93052cc112dSEd Tanous authMethodsConfig); 93178158631SZbigniew Kurzynski // Save configuration immediately 93252cc112dSEd Tanous persistent_data::getConfig().writeData(); 93378158631SZbigniew Kurzynski 93478158631SZbigniew Kurzynski messages::success(asyncResp->res); 93578158631SZbigniew Kurzynski } 93678158631SZbigniew Kurzynski 9378a07d286SRatan Gupta /** 9388a07d286SRatan Gupta * @brief Get the required values from the given JSON, validates the 9398a07d286SRatan Gupta * value and create the LDAP config object. 9408a07d286SRatan Gupta * @param input JSON data 9418a07d286SRatan Gupta * @param asyncResp pointer to the JSON response 9428a07d286SRatan Gupta * @param serverType Type of LDAP server(openLDAP/ActiveDirectory) 9438a07d286SRatan Gupta */ 9448a07d286SRatan Gupta 94510cb44f3SEd Tanous struct LdapPatchParams 94610cb44f3SEd Tanous { 94710cb44f3SEd Tanous std::optional<std::string> authType; 94810cb44f3SEd Tanous std::optional<std::vector<std::string>> serviceAddressList; 94910cb44f3SEd Tanous std::optional<bool> serviceEnabled; 95010cb44f3SEd Tanous std::optional<std::vector<std::string>> baseDNList; 95110cb44f3SEd Tanous std::optional<std::string> userNameAttribute; 95210cb44f3SEd Tanous std::optional<std::string> groupsAttribute; 95310cb44f3SEd Tanous std::optional<std::string> userName; 95410cb44f3SEd Tanous std::optional<std::string> password; 95510cb44f3SEd Tanous std::optional< 95610cb44f3SEd Tanous std::vector<std::variant<nlohmann::json::object_t, std::nullptr_t>>> 95710cb44f3SEd Tanous remoteRoleMapData; 95810cb44f3SEd Tanous }; 95910cb44f3SEd Tanous 96010cb44f3SEd Tanous inline void handleLDAPPatch(LdapPatchParams&& input, 9618d1b46d7Szhanghch05 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 9628a07d286SRatan Gupta const std::string& serverType) 9638a07d286SRatan Gupta { 964eb2bbe56SRatan Gupta std::string dbusObjectPath; 965eb2bbe56SRatan Gupta if (serverType == "ActiveDirectory") 966eb2bbe56SRatan Gupta { 9672c70f800SEd Tanous dbusObjectPath = adConfigObject; 968eb2bbe56SRatan Gupta } 969eb2bbe56SRatan Gupta else if (serverType == "LDAP") 970eb2bbe56SRatan Gupta { 97123a21a1cSEd Tanous dbusObjectPath = ldapConfigObjectName; 972eb2bbe56SRatan Gupta } 973cb13a392SEd Tanous else 974cb13a392SEd Tanous { 97510cb44f3SEd Tanous BMCWEB_LOG_ERROR("serverType wasn't AD or LDAP but was {}????", 97610cb44f3SEd Tanous serverType); 977cb13a392SEd Tanous return; 978cb13a392SEd Tanous } 979eb2bbe56SRatan Gupta 98010cb44f3SEd Tanous if (input.authType && *input.authType != "UsernameAndPassword") 9818a07d286SRatan Gupta { 98210cb44f3SEd Tanous messages::propertyValueNotInList(asyncResp->res, *input.authType, 983c1019828SEd Tanous "AuthenticationType"); 984c1019828SEd Tanous return; 9858a07d286SRatan Gupta } 986c1019828SEd Tanous 98710cb44f3SEd Tanous if (input.serviceAddressList) 9888a07d286SRatan Gupta { 98910cb44f3SEd Tanous if (input.serviceAddressList->empty()) 9908a07d286SRatan Gupta { 991e2616cc5SEd Tanous messages::propertyValueNotInList( 99210cb44f3SEd Tanous asyncResp->res, *input.serviceAddressList, "ServiceAddress"); 9938a07d286SRatan Gupta return; 9948a07d286SRatan Gupta } 9958a07d286SRatan Gupta } 99610cb44f3SEd Tanous if (input.baseDNList) 9978a07d286SRatan Gupta { 99810cb44f3SEd Tanous if (input.baseDNList->empty()) 9998a07d286SRatan Gupta { 100010cb44f3SEd Tanous messages::propertyValueNotInList(asyncResp->res, *input.baseDNList, 10018a07d286SRatan Gupta "BaseDistinguishedNames"); 10028a07d286SRatan Gupta return; 10038a07d286SRatan Gupta } 10048a07d286SRatan Gupta } 10058a07d286SRatan Gupta 10068a07d286SRatan Gupta // nothing to update, then return 100710cb44f3SEd Tanous if (!input.userName && !input.password && !input.serviceAddressList && 100810cb44f3SEd Tanous !input.baseDNList && !input.userNameAttribute && 100910cb44f3SEd Tanous !input.groupsAttribute && !input.serviceEnabled && 101010cb44f3SEd Tanous !input.remoteRoleMapData) 10118a07d286SRatan Gupta { 10128a07d286SRatan Gupta return; 10138a07d286SRatan Gupta } 10148a07d286SRatan Gupta 10158a07d286SRatan Gupta // Get the existing resource first then keep modifying 10168a07d286SRatan Gupta // whenever any property gets updated. 1017bd79bce8SPatrick Williams getLDAPConfigData(serverType, [asyncResp, input = std::move(input), 101810cb44f3SEd Tanous dbusObjectPath = std::move(dbusObjectPath)]( 1019bd79bce8SPatrick Williams bool success, 1020bd79bce8SPatrick Williams const LDAPConfigData& confData, 1021c1019828SEd Tanous const std::string& serverT) mutable { 10228a07d286SRatan Gupta if (!success) 10238a07d286SRatan Gupta { 10248a07d286SRatan Gupta messages::internalError(asyncResp->res); 10258a07d286SRatan Gupta return; 10268a07d286SRatan Gupta } 10276c51eab1SEd Tanous parseLDAPConfigData(asyncResp->res.jsonValue, confData, serverT); 10288a07d286SRatan Gupta if (confData.serviceEnabled) 10298a07d286SRatan Gupta { 10308a07d286SRatan Gupta // Disable the service first and update the rest of 10318a07d286SRatan Gupta // the properties. 10326c51eab1SEd Tanous handleServiceEnablePatch(false, asyncResp, serverT, dbusObjectPath); 10338a07d286SRatan Gupta } 10348a07d286SRatan Gupta 103510cb44f3SEd Tanous if (input.serviceAddressList) 10368a07d286SRatan Gupta { 103710cb44f3SEd Tanous handleServiceAddressPatch(*input.serviceAddressList, asyncResp, 103810cb44f3SEd Tanous serverT, dbusObjectPath); 103910cb44f3SEd Tanous } 104010cb44f3SEd Tanous if (input.userName) 104110cb44f3SEd Tanous { 104210cb44f3SEd Tanous handleUserNamePatch(*input.userName, asyncResp, serverT, 10436c51eab1SEd Tanous dbusObjectPath); 10448a07d286SRatan Gupta } 104510cb44f3SEd Tanous if (input.password) 10468a07d286SRatan Gupta { 104710cb44f3SEd Tanous handlePasswordPatch(*input.password, asyncResp, serverT, 104810cb44f3SEd Tanous dbusObjectPath); 10498a07d286SRatan Gupta } 10508a07d286SRatan Gupta 105110cb44f3SEd Tanous if (input.baseDNList) 10528a07d286SRatan Gupta { 105310cb44f3SEd Tanous handleBaseDNPatch(*input.baseDNList, asyncResp, serverT, 10546c51eab1SEd Tanous dbusObjectPath); 10558a07d286SRatan Gupta } 105610cb44f3SEd Tanous if (input.userNameAttribute) 10578a07d286SRatan Gupta { 105810cb44f3SEd Tanous handleUserNameAttrPatch(*input.userNameAttribute, asyncResp, 105910cb44f3SEd Tanous serverT, dbusObjectPath); 106010cb44f3SEd Tanous } 106110cb44f3SEd Tanous if (input.groupsAttribute) 106210cb44f3SEd Tanous { 106310cb44f3SEd Tanous handleGroupNameAttrPatch(*input.groupsAttribute, asyncResp, serverT, 10646c51eab1SEd Tanous dbusObjectPath); 10658a07d286SRatan Gupta } 106610cb44f3SEd Tanous if (input.serviceEnabled) 10678a07d286SRatan Gupta { 10688a07d286SRatan Gupta // if user has given the value as true then enable 10698a07d286SRatan Gupta // the service. if user has given false then no-op 10708a07d286SRatan Gupta // as service is already stopped. 107110cb44f3SEd Tanous if (*input.serviceEnabled) 10728a07d286SRatan Gupta { 107310cb44f3SEd Tanous handleServiceEnablePatch(*input.serviceEnabled, asyncResp, 107410cb44f3SEd Tanous serverT, dbusObjectPath); 10758a07d286SRatan Gupta } 10768a07d286SRatan Gupta } 10778a07d286SRatan Gupta else 10788a07d286SRatan Gupta { 10798a07d286SRatan Gupta // if user has not given the service enabled value 10808a07d286SRatan Gupta // then revert it to the same state as it was 10818a07d286SRatan Gupta // before. 10828a07d286SRatan Gupta handleServiceEnablePatch(confData.serviceEnabled, asyncResp, 108323a21a1cSEd Tanous serverT, dbusObjectPath); 10848a07d286SRatan Gupta } 108506785244SRatan Gupta 108610cb44f3SEd Tanous if (input.remoteRoleMapData) 108706785244SRatan Gupta { 10886c51eab1SEd Tanous handleRoleMapPatch(asyncResp, confData.groupRoleList, serverT, 108910cb44f3SEd Tanous *input.remoteRoleMapData); 109006785244SRatan Gupta } 10918a07d286SRatan Gupta }); 10928a07d286SRatan Gupta } 1093d4b5443fSEd Tanous 109458345856SAbhishek Patel inline void updateUserProperties( 109558345856SAbhishek Patel std::shared_ptr<bmcweb::AsyncResp> asyncResp, const std::string& username, 1096618c14b4SEd Tanous const std::optional<std::string>& password, 1097618c14b4SEd Tanous const std::optional<bool>& enabled, 109858345856SAbhishek Patel const std::optional<std::string>& roleId, const std::optional<bool>& locked, 1099e518ef32SRavi Teja std::optional<std::vector<std::string>> accountTypes, bool userSelf, 1100e518ef32SRavi Teja const std::shared_ptr<persistent_data::UserSession>& session) 11011abe55efSEd Tanous { 1102b477fd44SP Dheeraj Srujan Kumar sdbusplus::message::object_path tempObjPath(rootUserDbusPath); 1103b477fd44SP Dheeraj Srujan Kumar tempObjPath /= username; 1104b477fd44SP Dheeraj Srujan Kumar std::string dbusObjectPath(tempObjPath); 11056c51eab1SEd Tanous 11066c51eab1SEd Tanous dbus::utility::checkDbusPathExists( 1107e518ef32SRavi Teja dbusObjectPath, 1108e518ef32SRavi Teja [dbusObjectPath, username, password, roleId, enabled, locked, 1109e518ef32SRavi Teja accountTypes(std::move(accountTypes)), userSelf, session, 1110e518ef32SRavi Teja asyncResp{std::move(asyncResp)}](int rc) { 1111e662eae8SEd Tanous if (rc <= 0) 11126c51eab1SEd Tanous { 1113d8a5d5d8SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "ManagerAccount", 11146c51eab1SEd Tanous username); 11156c51eab1SEd Tanous return; 11166c51eab1SEd Tanous } 11176c51eab1SEd Tanous 11186c51eab1SEd Tanous if (password) 11196c51eab1SEd Tanous { 11206c51eab1SEd Tanous int retval = pamUpdatePassword(username, *password); 11216c51eab1SEd Tanous 11226c51eab1SEd Tanous if (retval == PAM_USER_UNKNOWN) 11236c51eab1SEd Tanous { 1124d8a5d5d8SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "ManagerAccount", 11256c51eab1SEd Tanous username); 11266c51eab1SEd Tanous } 11276c51eab1SEd Tanous else if (retval == PAM_AUTHTOK_ERR) 11286c51eab1SEd Tanous { 11296c51eab1SEd Tanous // If password is invalid 11309bd80831SJason M. Bills messages::propertyValueFormatError(asyncResp->res, nullptr, 11319bd80831SJason M. Bills "Password"); 113262598e31SEd Tanous BMCWEB_LOG_ERROR("pamUpdatePassword Failed"); 11336c51eab1SEd Tanous } 11346c51eab1SEd Tanous else if (retval != PAM_SUCCESS) 11356c51eab1SEd Tanous { 11366c51eab1SEd Tanous messages::internalError(asyncResp->res); 11376c51eab1SEd Tanous return; 11386c51eab1SEd Tanous } 1139e7b1b62bSEd Tanous else 1140e7b1b62bSEd Tanous { 1141bd79bce8SPatrick Williams // Remove existing sessions of the user when password 1142bd79bce8SPatrick Williams // changed 1143e518ef32SRavi Teja persistent_data::SessionStore::getInstance() 1144bd79bce8SPatrick Williams .removeSessionsByUsernameExceptSession(username, 1145bd79bce8SPatrick Williams session); 1146e7b1b62bSEd Tanous messages::success(asyncResp->res); 1147e7b1b62bSEd Tanous } 11486c51eab1SEd Tanous } 11496c51eab1SEd Tanous 11506c51eab1SEd Tanous if (enabled) 11516c51eab1SEd Tanous { 1152bd79bce8SPatrick Williams setDbusProperty( 1153bd79bce8SPatrick Williams asyncResp, "Enabled", "xyz.openbmc_project.User.Manager", 1154bd79bce8SPatrick Williams dbusObjectPath, "xyz.openbmc_project.User.Attributes", 1155e93abac6SGinu George "UserEnabled", *enabled); 11566c51eab1SEd Tanous } 11576c51eab1SEd Tanous 11586c51eab1SEd Tanous if (roleId) 11596c51eab1SEd Tanous { 11606c51eab1SEd Tanous std::string priv = getPrivilegeFromRoleId(*roleId); 11616c51eab1SEd Tanous if (priv.empty()) 11626c51eab1SEd Tanous { 1163e2616cc5SEd Tanous messages::propertyValueNotInList(asyncResp->res, true, 1164e2616cc5SEd Tanous "Locked"); 11656c51eab1SEd Tanous return; 11666c51eab1SEd Tanous } 1167bd79bce8SPatrick Williams setDbusProperty( 1168bd79bce8SPatrick Williams asyncResp, "RoleId", "xyz.openbmc_project.User.Manager", 1169bd79bce8SPatrick Williams dbusObjectPath, "xyz.openbmc_project.User.Attributes", 1170e93abac6SGinu George "UserPrivilege", priv); 11716c51eab1SEd Tanous } 11726c51eab1SEd Tanous 11736c51eab1SEd Tanous if (locked) 11746c51eab1SEd Tanous { 11756c51eab1SEd Tanous // admin can unlock the account which is locked by 11766c51eab1SEd Tanous // successive authentication failures but admin should 11776c51eab1SEd Tanous // not be allowed to lock an account. 11786c51eab1SEd Tanous if (*locked) 11796c51eab1SEd Tanous { 11806c51eab1SEd Tanous messages::propertyValueNotInList(asyncResp->res, "true", 11816c51eab1SEd Tanous "Locked"); 11826c51eab1SEd Tanous return; 11836c51eab1SEd Tanous } 1184bd79bce8SPatrick Williams setDbusProperty( 1185bd79bce8SPatrick Williams asyncResp, "Locked", "xyz.openbmc_project.User.Manager", 1186bd79bce8SPatrick Williams dbusObjectPath, "xyz.openbmc_project.User.Attributes", 1187e93abac6SGinu George "UserLockedForFailedAttempt", *locked); 11886c51eab1SEd Tanous } 118958345856SAbhishek Patel 119058345856SAbhishek Patel if (accountTypes) 119158345856SAbhishek Patel { 119258345856SAbhishek Patel patchAccountTypes(*accountTypes, asyncResp, dbusObjectPath, 119358345856SAbhishek Patel userSelf); 119458345856SAbhishek Patel } 11956c51eab1SEd Tanous }); 11966c51eab1SEd Tanous } 11976c51eab1SEd Tanous 11984c7d4d33SEd Tanous inline void handleAccountServiceHead( 11994c7d4d33SEd Tanous App& app, const crow::Request& req, 12001ef4c342SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 12016c51eab1SEd Tanous { 12023ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 120345ca1b86SEd Tanous { 120445ca1b86SEd Tanous return; 120545ca1b86SEd Tanous } 12064c7d4d33SEd Tanous asyncResp->res.addHeader( 12074c7d4d33SEd Tanous boost::beast::http::field::link, 12084c7d4d33SEd Tanous "</redfish/v1/JsonSchemas/AccountService/AccountService.json>; rel=describedby"); 12094c7d4d33SEd Tanous } 12104c7d4d33SEd Tanous 12114c7d4d33SEd Tanous inline void 12121aa375b8SEd Tanous getClientCertificates(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 12131aa375b8SEd Tanous const nlohmann::json::json_pointer& keyLocation) 12141aa375b8SEd Tanous { 12151aa375b8SEd Tanous boost::urls::url url( 12161aa375b8SEd Tanous "/redfish/v1/AccountService/MultiFactorAuth/ClientCertificate/Certificates"); 12171aa375b8SEd Tanous std::array<std::string_view, 1> interfaces = { 12181aa375b8SEd Tanous "xyz.openbmc_project.Certs.Certificate"}; 12191aa375b8SEd Tanous std::string path = "/xyz/openbmc_project/certs/authority/truststore"; 12201aa375b8SEd Tanous 12211aa375b8SEd Tanous collection_util::getCollectionToKey(asyncResp, url, interfaces, path, 12221aa375b8SEd Tanous keyLocation); 12231aa375b8SEd Tanous } 12241aa375b8SEd Tanous 12251aa375b8SEd Tanous inline void handleAccountServiceClientCertificatesInstanceHead( 12261aa375b8SEd Tanous App& app, const crow::Request& req, 12271aa375b8SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 12281aa375b8SEd Tanous const std::string& /*id*/) 12291aa375b8SEd Tanous { 12301aa375b8SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 12311aa375b8SEd Tanous { 12321aa375b8SEd Tanous return; 12331aa375b8SEd Tanous } 12341aa375b8SEd Tanous 12351aa375b8SEd Tanous asyncResp->res.addHeader( 12361aa375b8SEd Tanous boost::beast::http::field::link, 12371aa375b8SEd Tanous "</redfish/v1/JsonSchemas/Certificate/Certificate.json>; rel=describedby"); 12381aa375b8SEd Tanous } 12391aa375b8SEd Tanous 12401aa375b8SEd Tanous inline void handleAccountServiceClientCertificatesInstanceGet( 12411aa375b8SEd Tanous App& app, const crow::Request& req, 12421aa375b8SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id) 12431aa375b8SEd Tanous { 12441aa375b8SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 12451aa375b8SEd Tanous { 12461aa375b8SEd Tanous return; 12471aa375b8SEd Tanous } 12481aa375b8SEd Tanous BMCWEB_LOG_DEBUG("ClientCertificate Certificate ID={}", id); 12491aa375b8SEd Tanous const boost::urls::url certURL = boost::urls::format( 12501aa375b8SEd Tanous "/redfish/v1/AccountService/MultiFactorAuth/ClientCertificate/Certificates/{}", 12511aa375b8SEd Tanous id); 12521aa375b8SEd Tanous std::string objPath = 12531aa375b8SEd Tanous sdbusplus::message::object_path(certs::authorityObjectPath) / id; 12541aa375b8SEd Tanous getCertificateProperties( 12551aa375b8SEd Tanous asyncResp, objPath, 12561aa375b8SEd Tanous "xyz.openbmc_project.Certs.Manager.Authority.Truststore", id, certURL, 12571aa375b8SEd Tanous "Client Certificate"); 12581aa375b8SEd Tanous } 12591aa375b8SEd Tanous 12601aa375b8SEd Tanous inline void handleAccountServiceClientCertificatesHead( 12611aa375b8SEd Tanous App& app, const crow::Request& req, 12621aa375b8SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 12631aa375b8SEd Tanous { 12641aa375b8SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 12651aa375b8SEd Tanous { 12661aa375b8SEd Tanous return; 12671aa375b8SEd Tanous } 12681aa375b8SEd Tanous 12691aa375b8SEd Tanous asyncResp->res.addHeader( 12701aa375b8SEd Tanous boost::beast::http::field::link, 12711aa375b8SEd Tanous "</redfish/v1/JsonSchemas/CertificateCollection/CertificateCollection.json>; rel=describedby"); 12721aa375b8SEd Tanous } 12731aa375b8SEd Tanous 12741aa375b8SEd Tanous inline void handleAccountServiceClientCertificatesGet( 12751aa375b8SEd Tanous App& app, const crow::Request& req, 12761aa375b8SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 12771aa375b8SEd Tanous { 12781aa375b8SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 12791aa375b8SEd Tanous { 12801aa375b8SEd Tanous return; 12811aa375b8SEd Tanous } 12821aa375b8SEd Tanous getClientCertificates(asyncResp, "/Members"_json_pointer); 12831aa375b8SEd Tanous } 12841aa375b8SEd Tanous 12853ce3688aSEd Tanous using account_service::CertificateMappingAttribute; 12863ce3688aSEd Tanous using persistent_data::MTLSCommonNameParseMode; 12873ce3688aSEd Tanous inline CertificateMappingAttribute 12883ce3688aSEd Tanous getCertificateMapping(MTLSCommonNameParseMode parse) 12893ce3688aSEd Tanous { 12903ce3688aSEd Tanous switch (parse) 12913ce3688aSEd Tanous { 12923ce3688aSEd Tanous case MTLSCommonNameParseMode::CommonName: 12933ce3688aSEd Tanous { 12943ce3688aSEd Tanous return CertificateMappingAttribute::CommonName; 12953ce3688aSEd Tanous } 12963ce3688aSEd Tanous break; 12973ce3688aSEd Tanous case MTLSCommonNameParseMode::Whole: 12983ce3688aSEd Tanous { 12993ce3688aSEd Tanous return CertificateMappingAttribute::Whole; 13003ce3688aSEd Tanous } 13013ce3688aSEd Tanous break; 13023ce3688aSEd Tanous case MTLSCommonNameParseMode::UserPrincipalName: 13033ce3688aSEd Tanous { 13043ce3688aSEd Tanous return CertificateMappingAttribute::UserPrincipalName; 13053ce3688aSEd Tanous } 13063ce3688aSEd Tanous break; 13073ce3688aSEd Tanous 13083ce3688aSEd Tanous case MTLSCommonNameParseMode::Meta: 13093ce3688aSEd Tanous { 13103ce3688aSEd Tanous if constexpr (BMCWEB_META_TLS_COMMON_NAME_PARSING) 13113ce3688aSEd Tanous { 13123ce3688aSEd Tanous return CertificateMappingAttribute::CommonName; 13133ce3688aSEd Tanous } 13143ce3688aSEd Tanous } 13153ce3688aSEd Tanous break; 13163ce3688aSEd Tanous default: 13173ce3688aSEd Tanous { 13183ce3688aSEd Tanous return CertificateMappingAttribute::Invalid; 13193ce3688aSEd Tanous } 13203ce3688aSEd Tanous break; 13213ce3688aSEd Tanous } 13223ce3688aSEd Tanous } 13233ce3688aSEd Tanous 13241aa375b8SEd Tanous inline void 13254c7d4d33SEd Tanous handleAccountServiceGet(App& app, const crow::Request& req, 13264c7d4d33SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 13274c7d4d33SEd Tanous { 1328afd369c6SJiaqing Zhao if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 1329afd369c6SJiaqing Zhao { 1330afd369c6SJiaqing Zhao return; 1331afd369c6SJiaqing Zhao } 13323e72c202SNinad Palsule 13333e72c202SNinad Palsule if (req.session == nullptr) 13343e72c202SNinad Palsule { 13353e72c202SNinad Palsule messages::internalError(asyncResp->res); 13363e72c202SNinad Palsule return; 13373e72c202SNinad Palsule } 13383e72c202SNinad Palsule 1339c1019828SEd Tanous const persistent_data::AuthConfigMethods& authMethodsConfig = 1340c1019828SEd Tanous persistent_data::SessionStore::getInstance().getAuthMethodsConfig(); 1341c1019828SEd Tanous 1342afd369c6SJiaqing Zhao asyncResp->res.addHeader( 1343afd369c6SJiaqing Zhao boost::beast::http::field::link, 1344afd369c6SJiaqing Zhao "</redfish/v1/JsonSchemas/AccountService/AccountService.json>; rel=describedby"); 1345afd369c6SJiaqing Zhao 13461476687dSEd Tanous nlohmann::json& json = asyncResp->res.jsonValue; 13471476687dSEd Tanous json["@odata.id"] = "/redfish/v1/AccountService"; 1348482a69e7SRavi Teja json["@odata.type"] = "#AccountService.v1_15_0.AccountService"; 13491476687dSEd Tanous json["Id"] = "AccountService"; 13501476687dSEd Tanous json["Name"] = "Account Service"; 13511476687dSEd Tanous json["Description"] = "Account Service"; 13521476687dSEd Tanous json["ServiceEnabled"] = true; 13531476687dSEd Tanous json["MaxPasswordLength"] = 20; 13541ef4c342SEd Tanous json["Accounts"]["@odata.id"] = "/redfish/v1/AccountService/Accounts"; 13551476687dSEd Tanous json["Roles"]["@odata.id"] = "/redfish/v1/AccountService/Roles"; 1356482a69e7SRavi Teja json["HTTPBasicAuth"] = authMethodsConfig.basic 1357482a69e7SRavi Teja ? account_service::BasicAuthState::Enabled 1358482a69e7SRavi Teja : account_service::BasicAuthState::Disabled; 1359482a69e7SRavi Teja 1360482a69e7SRavi Teja nlohmann::json::array_t allowed; 1361482a69e7SRavi Teja allowed.emplace_back(account_service::BasicAuthState::Enabled); 1362482a69e7SRavi Teja allowed.emplace_back(account_service::BasicAuthState::Disabled); 1363482a69e7SRavi Teja json["HTTPBasicAuth@AllowableValues"] = std::move(allowed); 1364482a69e7SRavi Teja 13651aa375b8SEd Tanous nlohmann::json::object_t clientCertificate; 13661aa375b8SEd Tanous clientCertificate["Enabled"] = authMethodsConfig.tls; 13673281bcf1SEd Tanous clientCertificate["RespondToUnauthenticatedClients"] = 13683281bcf1SEd Tanous !authMethodsConfig.tlsStrict; 13693ce3688aSEd Tanous 13703ce3688aSEd Tanous using account_service::CertificateMappingAttribute; 13713ce3688aSEd Tanous 13723ce3688aSEd Tanous CertificateMappingAttribute mapping = 13733ce3688aSEd Tanous getCertificateMapping(authMethodsConfig.mTLSCommonNameParsingMode); 13743ce3688aSEd Tanous if (mapping == CertificateMappingAttribute::Invalid) 13753ce3688aSEd Tanous { 13763ce3688aSEd Tanous messages::internalError(asyncResp->res); 13773ce3688aSEd Tanous } 13783ce3688aSEd Tanous else 13793ce3688aSEd Tanous { 13803ce3688aSEd Tanous clientCertificate["CertificateMappingAttribute"] = mapping; 13813ce3688aSEd Tanous } 13821aa375b8SEd Tanous nlohmann::json::object_t certificates; 13831aa375b8SEd Tanous certificates["@odata.id"] = 13841aa375b8SEd Tanous "/redfish/v1/AccountService/MultiFactorAuth/ClientCertificate/Certificates"; 13851aa375b8SEd Tanous certificates["@odata.type"] = 13861aa375b8SEd Tanous "#CertificateCollection.CertificateCollection"; 13871aa375b8SEd Tanous clientCertificate["Certificates"] = std::move(certificates); 13881aa375b8SEd Tanous json["MultiFactorAuth"]["ClientCertificate"] = std::move(clientCertificate); 13891aa375b8SEd Tanous 13901aa375b8SEd Tanous getClientCertificates( 13911aa375b8SEd Tanous asyncResp, 13921aa375b8SEd Tanous "/MultiFactorAuth/ClientCertificate/Certificates/Members"_json_pointer); 13931aa375b8SEd Tanous 13941476687dSEd Tanous json["Oem"]["OpenBMC"]["@odata.type"] = 13955b5574acSEd Tanous "#OpenBMCAccountService.v1_0_0.AccountService"; 13961476687dSEd Tanous json["Oem"]["OpenBMC"]["@odata.id"] = 13971476687dSEd Tanous "/redfish/v1/AccountService#/Oem/OpenBMC"; 13981476687dSEd Tanous json["Oem"]["OpenBMC"]["AuthMethods"]["BasicAuth"] = 13991476687dSEd Tanous authMethodsConfig.basic; 14001476687dSEd Tanous json["Oem"]["OpenBMC"]["AuthMethods"]["SessionToken"] = 14011476687dSEd Tanous authMethodsConfig.sessionToken; 14021ef4c342SEd Tanous json["Oem"]["OpenBMC"]["AuthMethods"]["XToken"] = authMethodsConfig.xtoken; 14031ef4c342SEd Tanous json["Oem"]["OpenBMC"]["AuthMethods"]["Cookie"] = authMethodsConfig.cookie; 14041ef4c342SEd Tanous json["Oem"]["OpenBMC"]["AuthMethods"]["TLS"] = authMethodsConfig.tls; 14051476687dSEd Tanous 14061ef4c342SEd Tanous // /redfish/v1/AccountService/LDAP/Certificates is something only 14071ef4c342SEd Tanous // ConfigureManager can access then only display when the user has 14081ef4c342SEd Tanous // permissions ConfigureManager 140972048780SAbhishek Patel Privileges effectiveUserPrivileges = 14103e72c202SNinad Palsule redfish::getUserPrivileges(*req.session); 141172048780SAbhishek Patel 141272048780SAbhishek Patel if (isOperationAllowedWithPrivileges({{"ConfigureManager"}}, 141372048780SAbhishek Patel effectiveUserPrivileges)) 141472048780SAbhishek Patel { 14151ef4c342SEd Tanous asyncResp->res.jsonValue["LDAP"]["Certificates"]["@odata.id"] = 14161476687dSEd Tanous "/redfish/v1/AccountService/LDAP/Certificates"; 141772048780SAbhishek Patel } 1418d1bde9e5SKrzysztof Grobelny sdbusplus::asio::getAllProperties( 1419d1bde9e5SKrzysztof Grobelny *crow::connections::systemBus, "xyz.openbmc_project.User.Manager", 1420d1bde9e5SKrzysztof Grobelny "/xyz/openbmc_project/user", "xyz.openbmc_project.User.AccountPolicy", 14215e7e2dc5SEd Tanous [asyncResp](const boost::system::error_code& ec, 14221ef4c342SEd Tanous const dbus::utility::DBusPropertiesMap& propertiesList) { 14233d958bbcSAppaRao Puli if (ec) 14243d958bbcSAppaRao Puli { 14253d958bbcSAppaRao Puli messages::internalError(asyncResp->res); 14263d958bbcSAppaRao Puli return; 14273d958bbcSAppaRao Puli } 1428d1bde9e5SKrzysztof Grobelny 142962598e31SEd Tanous BMCWEB_LOG_DEBUG("Got {} properties for AccountService", 143062598e31SEd Tanous propertiesList.size()); 1431d1bde9e5SKrzysztof Grobelny 1432d1bde9e5SKrzysztof Grobelny const uint8_t* minPasswordLength = nullptr; 1433d1bde9e5SKrzysztof Grobelny const uint32_t* accountUnlockTimeout = nullptr; 1434d1bde9e5SKrzysztof Grobelny const uint16_t* maxLoginAttemptBeforeLockout = nullptr; 1435d1bde9e5SKrzysztof Grobelny 1436d1bde9e5SKrzysztof Grobelny const bool success = sdbusplus::unpackPropertiesNoThrow( 1437d1bde9e5SKrzysztof Grobelny dbus_utils::UnpackErrorPrinter(), propertiesList, 1438d1bde9e5SKrzysztof Grobelny "MinPasswordLength", minPasswordLength, "AccountUnlockTimeout", 1439d1bde9e5SKrzysztof Grobelny accountUnlockTimeout, "MaxLoginAttemptBeforeLockout", 1440d1bde9e5SKrzysztof Grobelny maxLoginAttemptBeforeLockout); 1441d1bde9e5SKrzysztof Grobelny 1442d1bde9e5SKrzysztof Grobelny if (!success) 14433d958bbcSAppaRao Puli { 1444d1bde9e5SKrzysztof Grobelny messages::internalError(asyncResp->res); 1445d1bde9e5SKrzysztof Grobelny return; 14463d958bbcSAppaRao Puli } 1447d1bde9e5SKrzysztof Grobelny 1448d1bde9e5SKrzysztof Grobelny if (minPasswordLength != nullptr) 14493d958bbcSAppaRao Puli { 1450bd79bce8SPatrick Williams asyncResp->res.jsonValue["MinPasswordLength"] = 1451bd79bce8SPatrick Williams *minPasswordLength; 14523d958bbcSAppaRao Puli } 1453d1bde9e5SKrzysztof Grobelny 1454d1bde9e5SKrzysztof Grobelny if (accountUnlockTimeout != nullptr) 14553d958bbcSAppaRao Puli { 1456d1bde9e5SKrzysztof Grobelny asyncResp->res.jsonValue["AccountLockoutDuration"] = 1457d1bde9e5SKrzysztof Grobelny *accountUnlockTimeout; 1458d1bde9e5SKrzysztof Grobelny } 1459d1bde9e5SKrzysztof Grobelny 1460d1bde9e5SKrzysztof Grobelny if (maxLoginAttemptBeforeLockout != nullptr) 14613d958bbcSAppaRao Puli { 1462002d39b4SEd Tanous asyncResp->res.jsonValue["AccountLockoutThreshold"] = 1463d1bde9e5SKrzysztof Grobelny *maxLoginAttemptBeforeLockout; 14643d958bbcSAppaRao Puli } 1465d1bde9e5SKrzysztof Grobelny }); 14666973a582SRatan Gupta 146702cad96eSEd Tanous auto callback = [asyncResp](bool success, const LDAPConfigData& confData, 1468ab828d7cSRatan Gupta const std::string& ldapType) { 1469cb13a392SEd Tanous if (!success) 1470cb13a392SEd Tanous { 1471cb13a392SEd Tanous return; 1472cb13a392SEd Tanous } 1473002d39b4SEd Tanous parseLDAPConfigData(asyncResp->res.jsonValue, confData, ldapType); 1474ab828d7cSRatan Gupta }; 1475ab828d7cSRatan Gupta 1476ab828d7cSRatan Gupta getLDAPConfigData("LDAP", callback); 1477ab828d7cSRatan Gupta getLDAPConfigData("ActiveDirectory", callback); 14781ef4c342SEd Tanous } 14796973a582SRatan Gupta 1480bd79bce8SPatrick Williams inline void handleCertificateMappingAttributePatch( 1481bd79bce8SPatrick Williams crow::Response& res, const std::string& certMapAttribute) 14823ce3688aSEd Tanous { 14833ce3688aSEd Tanous MTLSCommonNameParseMode parseMode = 14843ce3688aSEd Tanous persistent_data::getMTLSCommonNameParseMode(certMapAttribute); 14853ce3688aSEd Tanous if (parseMode == MTLSCommonNameParseMode::Invalid) 14863ce3688aSEd Tanous { 14873ce3688aSEd Tanous messages::propertyValueNotInList(res, "CertificateMappingAttribute", 14883ce3688aSEd Tanous certMapAttribute); 14893ce3688aSEd Tanous return; 14903ce3688aSEd Tanous } 14913ce3688aSEd Tanous 14923ce3688aSEd Tanous persistent_data::AuthConfigMethods& authMethodsConfig = 14933ce3688aSEd Tanous persistent_data::SessionStore::getInstance().getAuthMethodsConfig(); 14943ce3688aSEd Tanous authMethodsConfig.mTLSCommonNameParsingMode = parseMode; 14953ce3688aSEd Tanous } 14963ce3688aSEd Tanous 14973281bcf1SEd Tanous inline void handleRespondToUnauthenticatedClientsPatch( 14983281bcf1SEd Tanous App& app, const crow::Request& req, crow::Response& res, 14993281bcf1SEd Tanous bool respondToUnauthenticatedClients) 15003281bcf1SEd Tanous { 15013281bcf1SEd Tanous if (req.session != nullptr) 15023281bcf1SEd Tanous { 15033281bcf1SEd Tanous // Sanity check. If the user isn't currently authenticated with mutual 15043281bcf1SEd Tanous // TLS, they very likely are about to permanently lock themselves out. 15053281bcf1SEd Tanous // Make sure they're using mutual TLS before allowing locking. 15063281bcf1SEd Tanous if (req.session->sessionType != persistent_data::SessionType::MutualTLS) 15073281bcf1SEd Tanous { 15083281bcf1SEd Tanous messages::propertyValueExternalConflict( 15093281bcf1SEd Tanous res, 15103281bcf1SEd Tanous "MultiFactorAuth/ClientCertificate/RespondToUnauthenticatedClients", 15113281bcf1SEd Tanous respondToUnauthenticatedClients); 15123281bcf1SEd Tanous return; 15133281bcf1SEd Tanous } 15143281bcf1SEd Tanous } 15153281bcf1SEd Tanous 15163281bcf1SEd Tanous persistent_data::AuthConfigMethods& authMethodsConfig = 15173281bcf1SEd Tanous persistent_data::SessionStore::getInstance().getAuthMethodsConfig(); 15183281bcf1SEd Tanous 15193281bcf1SEd Tanous // Change the settings 15203281bcf1SEd Tanous authMethodsConfig.tlsStrict = !respondToUnauthenticatedClients; 15213281bcf1SEd Tanous 15223281bcf1SEd Tanous // Write settings to disk 15233281bcf1SEd Tanous persistent_data::getConfig().writeData(); 15243281bcf1SEd Tanous 15253281bcf1SEd Tanous // Trigger a reload, to apply the new settings to new connections 15263281bcf1SEd Tanous app.loadCertificate(); 15273281bcf1SEd Tanous } 15283281bcf1SEd Tanous 15291ef4c342SEd Tanous inline void handleAccountServicePatch( 15301ef4c342SEd Tanous App& app, const crow::Request& req, 15311ef4c342SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 15321ef4c342SEd Tanous { 15333ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 153445ca1b86SEd Tanous { 153545ca1b86SEd Tanous return; 153645ca1b86SEd Tanous } 1537f5ffd806SEd Tanous std::optional<uint32_t> unlockTimeout; 1538f5ffd806SEd Tanous std::optional<uint16_t> lockoutThreshold; 1539ef73ad0dSPaul Fertser std::optional<uint8_t> minPasswordLength; 1540f5ffd806SEd Tanous std::optional<uint16_t> maxPasswordLength; 154110cb44f3SEd Tanous LdapPatchParams ldapObject; 15423ce3688aSEd Tanous std::optional<std::string> certificateMappingAttribute; 15433281bcf1SEd Tanous std::optional<bool> respondToUnauthenticatedClients; 154410cb44f3SEd Tanous LdapPatchParams activeDirectoryObject; 1545c1019828SEd Tanous AuthMethods auth; 1546482a69e7SRavi Teja std::optional<std::string> httpBasicAuth; 15473ce3688aSEd Tanous 1548*afc474aeSMyung Bae if (!json_util::readJsonPatch( // 1549*afc474aeSMyung Bae req, asyncResp->res, // 1550*afc474aeSMyung Bae "AccountLockoutDuration", unlockTimeout, // 1551*afc474aeSMyung Bae "AccountLockoutThreshold", lockoutThreshold, // 1552*afc474aeSMyung Bae "ActiveDirectory/Authentication/AuthenticationType", 1553*afc474aeSMyung Bae activeDirectoryObject.authType, // 1554*afc474aeSMyung Bae "ActiveDirectory/Authentication/Password", 1555*afc474aeSMyung Bae activeDirectoryObject.password, // 1556*afc474aeSMyung Bae "ActiveDirectory/Authentication/Username", 1557*afc474aeSMyung Bae activeDirectoryObject.userName, // 1558*afc474aeSMyung Bae "ActiveDirectory/LDAPService/SearchSettings/BaseDistinguishedNames", 1559*afc474aeSMyung Bae activeDirectoryObject.baseDNList, // 1560*afc474aeSMyung Bae "ActiveDirectory/LDAPService/SearchSettings/GroupsAttribute", 1561*afc474aeSMyung Bae activeDirectoryObject.groupsAttribute, // 1562*afc474aeSMyung Bae "ActiveDirectory/LDAPService/SearchSettings/UsernameAttribute", 1563*afc474aeSMyung Bae activeDirectoryObject.userNameAttribute, // 1564*afc474aeSMyung Bae "ActiveDirectory/RemoteRoleMapping", 1565*afc474aeSMyung Bae activeDirectoryObject.remoteRoleMapData, // 1566*afc474aeSMyung Bae "ActiveDirectory/ServiceAddresses", 1567*afc474aeSMyung Bae activeDirectoryObject.serviceAddressList, // 1568*afc474aeSMyung Bae "ActiveDirectory/ServiceEnabled", 1569*afc474aeSMyung Bae activeDirectoryObject.serviceEnabled, // 1570*afc474aeSMyung Bae "HTTPBasicAuth", httpBasicAuth, // 1571*afc474aeSMyung Bae "LDAP/Authentication/AuthenticationType", ldapObject.authType, // 1572*afc474aeSMyung Bae "LDAP/Authentication/Password", ldapObject.password, // 1573*afc474aeSMyung Bae "LDAP/Authentication/Username", ldapObject.userName, // 1574*afc474aeSMyung Bae "LDAP/LDAPService/SearchSettings/BaseDistinguishedNames", 1575*afc474aeSMyung Bae ldapObject.baseDNList, // 1576*afc474aeSMyung Bae "LDAP/LDAPService/SearchSettings/GroupsAttribute", 1577*afc474aeSMyung Bae ldapObject.groupsAttribute, // 1578*afc474aeSMyung Bae "LDAP/LDAPService/SearchSettings/UsernameAttribute", 1579*afc474aeSMyung Bae ldapObject.userNameAttribute, // 1580*afc474aeSMyung Bae "LDAP/RemoteRoleMapping", ldapObject.remoteRoleMapData, // 1581*afc474aeSMyung Bae "LDAP/ServiceAddresses", ldapObject.serviceAddressList, // 1582*afc474aeSMyung Bae "LDAP/ServiceEnabled", ldapObject.serviceEnabled, // 1583*afc474aeSMyung Bae "MaxPasswordLength", maxPasswordLength, // 1584*afc474aeSMyung Bae "MinPasswordLength", minPasswordLength, // 1585*afc474aeSMyung Bae "MultiFactorAuth/ClientCertificate/CertificateMappingAttribute", 1586*afc474aeSMyung Bae certificateMappingAttribute, // 1587*afc474aeSMyung Bae "MultiFactorAuth/ClientCertificate/RespondToUnauthenticatedClients", 1588*afc474aeSMyung Bae respondToUnauthenticatedClients, // 1589*afc474aeSMyung Bae "Oem/OpenBMC/AuthMethods/BasicAuth", auth.basicAuth, // 1590*afc474aeSMyung Bae "Oem/OpenBMC/AuthMethods/Cookie", auth.cookie, // 1591*afc474aeSMyung Bae "Oem/OpenBMC/AuthMethods/SessionToken", auth.sessionToken, // 1592*afc474aeSMyung Bae "Oem/OpenBMC/AuthMethods/TLS", auth.tls, // 1593*afc474aeSMyung Bae "Oem/OpenBMC/AuthMethods/XToken", auth.xToken // 1594*afc474aeSMyung Bae )) 1595f5ffd806SEd Tanous { 1596f5ffd806SEd Tanous return; 1597f5ffd806SEd Tanous } 1598f5ffd806SEd Tanous 1599482a69e7SRavi Teja if (httpBasicAuth) 1600482a69e7SRavi Teja { 1601482a69e7SRavi Teja if (*httpBasicAuth == "Enabled") 1602482a69e7SRavi Teja { 1603482a69e7SRavi Teja auth.basicAuth = true; 1604482a69e7SRavi Teja } 1605482a69e7SRavi Teja else if (*httpBasicAuth == "Disabled") 1606482a69e7SRavi Teja { 1607482a69e7SRavi Teja auth.basicAuth = false; 1608482a69e7SRavi Teja } 1609482a69e7SRavi Teja else 1610482a69e7SRavi Teja { 1611482a69e7SRavi Teja messages::propertyValueNotInList(asyncResp->res, "HttpBasicAuth", 1612482a69e7SRavi Teja *httpBasicAuth); 1613482a69e7SRavi Teja } 1614482a69e7SRavi Teja } 1615482a69e7SRavi Teja 16163281bcf1SEd Tanous if (respondToUnauthenticatedClients) 16173281bcf1SEd Tanous { 16183281bcf1SEd Tanous handleRespondToUnauthenticatedClientsPatch( 16193281bcf1SEd Tanous app, req, asyncResp->res, *respondToUnauthenticatedClients); 16203281bcf1SEd Tanous } 16213281bcf1SEd Tanous 16223ce3688aSEd Tanous if (certificateMappingAttribute) 16233ce3688aSEd Tanous { 16243ce3688aSEd Tanous handleCertificateMappingAttributePatch(asyncResp->res, 16253ce3688aSEd Tanous *certificateMappingAttribute); 16263ce3688aSEd Tanous } 16273ce3688aSEd Tanous 1628f5ffd806SEd Tanous if (minPasswordLength) 1629f5ffd806SEd Tanous { 1630d02aad39SEd Tanous setDbusProperty( 1631e93abac6SGinu George asyncResp, "MinPasswordLength", "xyz.openbmc_project.User.Manager", 1632d02aad39SEd Tanous sdbusplus::message::object_path("/xyz/openbmc_project/user"), 16339ae226faSGeorge Liu "xyz.openbmc_project.User.AccountPolicy", "MinPasswordLength", 1634e93abac6SGinu George *minPasswordLength); 1635f5ffd806SEd Tanous } 1636f5ffd806SEd Tanous 1637f5ffd806SEd Tanous if (maxPasswordLength) 1638f5ffd806SEd Tanous { 16391ef4c342SEd Tanous messages::propertyNotWritable(asyncResp->res, "MaxPasswordLength"); 1640f5ffd806SEd Tanous } 1641f5ffd806SEd Tanous 164210cb44f3SEd Tanous handleLDAPPatch(std::move(activeDirectoryObject), asyncResp, 164310cb44f3SEd Tanous "ActiveDirectory"); 164410cb44f3SEd Tanous handleLDAPPatch(std::move(ldapObject), asyncResp, "LDAP"); 1645f5ffd806SEd Tanous 1646c1019828SEd Tanous handleAuthMethodsPatch(asyncResp, auth); 1647f5ffd806SEd Tanous 1648f5ffd806SEd Tanous if (unlockTimeout) 1649f5ffd806SEd Tanous { 1650d02aad39SEd Tanous setDbusProperty( 1651e93abac6SGinu George asyncResp, "AccountLockoutDuration", 1652e93abac6SGinu George "xyz.openbmc_project.User.Manager", 1653d02aad39SEd Tanous sdbusplus::message::object_path("/xyz/openbmc_project/user"), 16549ae226faSGeorge Liu "xyz.openbmc_project.User.AccountPolicy", "AccountUnlockTimeout", 1655e93abac6SGinu George *unlockTimeout); 1656f5ffd806SEd Tanous } 1657f5ffd806SEd Tanous if (lockoutThreshold) 1658f5ffd806SEd Tanous { 1659d02aad39SEd Tanous setDbusProperty( 1660e93abac6SGinu George asyncResp, "AccountLockoutThreshold", 1661e93abac6SGinu George "xyz.openbmc_project.User.Manager", 1662d02aad39SEd Tanous sdbusplus::message::object_path("/xyz/openbmc_project/user"), 16639ae226faSGeorge Liu "xyz.openbmc_project.User.AccountPolicy", 1664e93abac6SGinu George "MaxLoginAttemptBeforeLockout", *lockoutThreshold); 1665f5ffd806SEd Tanous } 16661ef4c342SEd Tanous } 1667f5ffd806SEd Tanous 16684c7d4d33SEd Tanous inline void handleAccountCollectionHead( 16691ef4c342SEd Tanous App& app, const crow::Request& req, 16701ef4c342SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 16711ef4c342SEd Tanous { 16723ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 167345ca1b86SEd Tanous { 167445ca1b86SEd Tanous return; 167545ca1b86SEd Tanous } 16764c7d4d33SEd Tanous asyncResp->res.addHeader( 16774c7d4d33SEd Tanous boost::beast::http::field::link, 16784c7d4d33SEd Tanous "</redfish/v1/JsonSchemas/ManagerAccountCollection.json>; rel=describedby"); 16794c7d4d33SEd Tanous } 16804c7d4d33SEd Tanous 16814c7d4d33SEd Tanous inline void handleAccountCollectionGet( 16824c7d4d33SEd Tanous App& app, const crow::Request& req, 16834c7d4d33SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 16844c7d4d33SEd Tanous { 1685afd369c6SJiaqing Zhao if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 1686afd369c6SJiaqing Zhao { 1687afd369c6SJiaqing Zhao return; 1688afd369c6SJiaqing Zhao } 16893e72c202SNinad Palsule 16903e72c202SNinad Palsule if (req.session == nullptr) 16913e72c202SNinad Palsule { 16923e72c202SNinad Palsule messages::internalError(asyncResp->res); 16933e72c202SNinad Palsule return; 16943e72c202SNinad Palsule } 16953e72c202SNinad Palsule 1696afd369c6SJiaqing Zhao asyncResp->res.addHeader( 1697afd369c6SJiaqing Zhao boost::beast::http::field::link, 1698afd369c6SJiaqing Zhao "</redfish/v1/JsonSchemas/ManagerAccountCollection.json>; rel=describedby"); 16991476687dSEd Tanous 17001476687dSEd Tanous asyncResp->res.jsonValue["@odata.id"] = 17011476687dSEd Tanous "/redfish/v1/AccountService/Accounts"; 17021ef4c342SEd Tanous asyncResp->res.jsonValue["@odata.type"] = "#ManagerAccountCollection." 17031476687dSEd Tanous "ManagerAccountCollection"; 17041476687dSEd Tanous asyncResp->res.jsonValue["Name"] = "Accounts Collection"; 17051476687dSEd Tanous asyncResp->res.jsonValue["Description"] = "BMC User Accounts"; 17060f74e643SEd Tanous 17076c51eab1SEd Tanous Privileges effectiveUserPrivileges = 17083e72c202SNinad Palsule redfish::getUserPrivileges(*req.session); 17096c51eab1SEd Tanous 1710f5e29f33SJunLin Chen std::string thisUser; 1711f5e29f33SJunLin Chen if (req.session) 1712f5e29f33SJunLin Chen { 1713f5e29f33SJunLin Chen thisUser = req.session->username; 1714f5e29f33SJunLin Chen } 17155eb468daSGeorge Liu sdbusplus::message::object_path path("/xyz/openbmc_project/user"); 17165eb468daSGeorge Liu dbus::utility::getManagedObjects( 17175eb468daSGeorge Liu "xyz.openbmc_project.User.Manager", path, 1718cef1ddfbSEd Tanous [asyncResp, thisUser, effectiveUserPrivileges]( 17195e7e2dc5SEd Tanous const boost::system::error_code& ec, 1720711ac7a9SEd Tanous const dbus::utility::ManagedObjectType& users) { 1721b9b2e0b2SEd Tanous if (ec) 1722b9b2e0b2SEd Tanous { 1723f12894f8SJason M. Bills messages::internalError(asyncResp->res); 1724b9b2e0b2SEd Tanous return; 1725b9b2e0b2SEd Tanous } 1726b9b2e0b2SEd Tanous 1727cef1ddfbSEd Tanous bool userCanSeeAllAccounts = 1728002d39b4SEd Tanous effectiveUserPrivileges.isSupersetOf({"ConfigureUsers"}); 1729cef1ddfbSEd Tanous 1730cef1ddfbSEd Tanous bool userCanSeeSelf = 1731002d39b4SEd Tanous effectiveUserPrivileges.isSupersetOf({"ConfigureSelf"}); 1732cef1ddfbSEd Tanous 1733002d39b4SEd Tanous nlohmann::json& memberArray = asyncResp->res.jsonValue["Members"]; 1734b9b2e0b2SEd Tanous memberArray = nlohmann::json::array(); 1735b9b2e0b2SEd Tanous 17369eb808c1SEd Tanous for (const auto& userpath : users) 1737b9b2e0b2SEd Tanous { 17382dfd18efSEd Tanous std::string user = userpath.first.filename(); 17392dfd18efSEd Tanous if (user.empty()) 1740b9b2e0b2SEd Tanous { 17412dfd18efSEd Tanous messages::internalError(asyncResp->res); 174262598e31SEd Tanous BMCWEB_LOG_ERROR("Invalid firmware ID"); 17432dfd18efSEd Tanous 17442dfd18efSEd Tanous return; 1745b9b2e0b2SEd Tanous } 1746f365910cSGunnar Mills 1747f365910cSGunnar Mills // As clarified by Redfish here: 1748f365910cSGunnar Mills // https://redfishforum.com/thread/281/manageraccountcollection-change-allows-account-enumeration 17496c51eab1SEd Tanous // Users without ConfigureUsers, only see their own 17506c51eab1SEd Tanous // account. Users with ConfigureUsers, see all 17516c51eab1SEd Tanous // accounts. 1752bd79bce8SPatrick Williams if (userCanSeeAllAccounts || 1753bd79bce8SPatrick Williams (thisUser == user && userCanSeeSelf)) 1754f365910cSGunnar Mills { 17551476687dSEd Tanous nlohmann::json::object_t member; 17563b32780dSEd Tanous member["@odata.id"] = boost::urls::format( 17573b32780dSEd Tanous "/redfish/v1/AccountService/Accounts/{}", user); 1758b2ba3072SPatrick Williams memberArray.emplace_back(std::move(member)); 1759b9b2e0b2SEd Tanous } 1760f365910cSGunnar Mills } 1761bd79bce8SPatrick Williams asyncResp->res.jsonValue["Members@odata.count"] = 1762bd79bce8SPatrick Williams memberArray.size(); 17635eb468daSGeorge Liu }); 17641ef4c342SEd Tanous } 17656c51eab1SEd Tanous 176697e90da3SNinad Palsule inline void processAfterCreateUser( 176797e90da3SNinad Palsule const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 176897e90da3SNinad Palsule const std::string& username, const std::string& password, 176997e90da3SNinad Palsule const boost::system::error_code& ec, sdbusplus::message_t& m) 177097e90da3SNinad Palsule { 177197e90da3SNinad Palsule if (ec) 177297e90da3SNinad Palsule { 177397e90da3SNinad Palsule userErrorMessageHandler(m.get_error(), asyncResp, username, ""); 177497e90da3SNinad Palsule return; 177597e90da3SNinad Palsule } 177697e90da3SNinad Palsule 177797e90da3SNinad Palsule if (pamUpdatePassword(username, password) != PAM_SUCCESS) 177897e90da3SNinad Palsule { 177997e90da3SNinad Palsule // At this point we have a user that's been 178097e90da3SNinad Palsule // created, but the password set 178197e90da3SNinad Palsule // failed.Something is wrong, so delete the user 178297e90da3SNinad Palsule // that we've already created 178397e90da3SNinad Palsule sdbusplus::message::object_path tempObjPath(rootUserDbusPath); 178497e90da3SNinad Palsule tempObjPath /= username; 178597e90da3SNinad Palsule const std::string userPath(tempObjPath); 178697e90da3SNinad Palsule 178797e90da3SNinad Palsule crow::connections::systemBus->async_method_call( 178897e90da3SNinad Palsule [asyncResp, password](const boost::system::error_code& ec3) { 178997e90da3SNinad Palsule if (ec3) 179097e90da3SNinad Palsule { 179197e90da3SNinad Palsule messages::internalError(asyncResp->res); 179297e90da3SNinad Palsule return; 179397e90da3SNinad Palsule } 179497e90da3SNinad Palsule 179597e90da3SNinad Palsule // If password is invalid 17969bd80831SJason M. Bills messages::propertyValueFormatError(asyncResp->res, nullptr, 179797e90da3SNinad Palsule "Password"); 179897e90da3SNinad Palsule }, 179997e90da3SNinad Palsule "xyz.openbmc_project.User.Manager", userPath, 180097e90da3SNinad Palsule "xyz.openbmc_project.Object.Delete", "Delete"); 180197e90da3SNinad Palsule 180262598e31SEd Tanous BMCWEB_LOG_ERROR("pamUpdatePassword Failed"); 180397e90da3SNinad Palsule return; 180497e90da3SNinad Palsule } 180597e90da3SNinad Palsule 180697e90da3SNinad Palsule messages::created(asyncResp->res); 180797e90da3SNinad Palsule asyncResp->res.addHeader("Location", 180897e90da3SNinad Palsule "/redfish/v1/AccountService/Accounts/" + username); 180997e90da3SNinad Palsule } 181097e90da3SNinad Palsule 181197e90da3SNinad Palsule inline void processAfterGetAllGroups( 181297e90da3SNinad Palsule const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 181397e90da3SNinad Palsule const std::string& username, const std::string& password, 1814e01d0c36SEd Tanous const std::string& roleId, bool enabled, 18159ba73934SNinad Palsule std::optional<std::vector<std::string>> accountTypes, 181697e90da3SNinad Palsule const std::vector<std::string>& allGroupsList) 181797e90da3SNinad Palsule { 18183e72c202SNinad Palsule std::vector<std::string> userGroups; 18199ba73934SNinad Palsule std::vector<std::string> accountTypeUserGroups; 18209ba73934SNinad Palsule 18219ba73934SNinad Palsule // If user specified account types then convert them to unix user groups 18229ba73934SNinad Palsule if (accountTypes) 18239ba73934SNinad Palsule { 18249ba73934SNinad Palsule if (!getUserGroupFromAccountType(asyncResp->res, *accountTypes, 18259ba73934SNinad Palsule accountTypeUserGroups)) 18269ba73934SNinad Palsule { 18279ba73934SNinad Palsule // Problem in mapping Account Types to User Groups, Error already 18289ba73934SNinad Palsule // logged. 18299ba73934SNinad Palsule return; 18309ba73934SNinad Palsule } 18319ba73934SNinad Palsule } 18329ba73934SNinad Palsule 18333e72c202SNinad Palsule for (const auto& grp : allGroupsList) 18343e72c202SNinad Palsule { 18359ba73934SNinad Palsule // If user specified the account type then only accept groups which are 18369ba73934SNinad Palsule // in the account types group list. 18379ba73934SNinad Palsule if (!accountTypeUserGroups.empty()) 18389ba73934SNinad Palsule { 18399ba73934SNinad Palsule bool found = false; 18409ba73934SNinad Palsule for (const auto& grp1 : accountTypeUserGroups) 18419ba73934SNinad Palsule { 18429ba73934SNinad Palsule if (grp == grp1) 18439ba73934SNinad Palsule { 18449ba73934SNinad Palsule found = true; 18459ba73934SNinad Palsule break; 18469ba73934SNinad Palsule } 18479ba73934SNinad Palsule } 18489ba73934SNinad Palsule if (!found) 18499ba73934SNinad Palsule { 18509ba73934SNinad Palsule continue; 18519ba73934SNinad Palsule } 18529ba73934SNinad Palsule } 18539ba73934SNinad Palsule 18543e72c202SNinad Palsule // Console access is provided to the user who is a member of 18553e72c202SNinad Palsule // hostconsole group and has a administrator role. So, set 18563e72c202SNinad Palsule // hostconsole group only for the administrator. 18579ba73934SNinad Palsule if ((grp == "hostconsole") && (roleId != "priv-admin")) 18583e72c202SNinad Palsule { 18599ba73934SNinad Palsule if (!accountTypeUserGroups.empty()) 18609ba73934SNinad Palsule { 186162598e31SEd Tanous BMCWEB_LOG_ERROR( 186262598e31SEd Tanous "Only administrator can get HostConsole access"); 18639ba73934SNinad Palsule asyncResp->res.result(boost::beast::http::status::bad_request); 18649ba73934SNinad Palsule return; 18659ba73934SNinad Palsule } 18669ba73934SNinad Palsule continue; 18679ba73934SNinad Palsule } 18683e72c202SNinad Palsule userGroups.emplace_back(grp); 18693e72c202SNinad Palsule } 18709ba73934SNinad Palsule 18719ba73934SNinad Palsule // Make sure user specified groups are valid. This is internal error because 18729ba73934SNinad Palsule // it some inconsistencies between user manager and bmcweb. 18739ba73934SNinad Palsule if (!accountTypeUserGroups.empty() && 18749ba73934SNinad Palsule accountTypeUserGroups.size() != userGroups.size()) 18759ba73934SNinad Palsule { 18769ba73934SNinad Palsule messages::internalError(asyncResp->res); 18779ba73934SNinad Palsule return; 18783e72c202SNinad Palsule } 187997e90da3SNinad Palsule crow::connections::systemBus->async_method_call( 188097e90da3SNinad Palsule [asyncResp, username, password](const boost::system::error_code& ec2, 188197e90da3SNinad Palsule sdbusplus::message_t& m) { 188297e90da3SNinad Palsule processAfterCreateUser(asyncResp, username, password, ec2, m); 188397e90da3SNinad Palsule }, 188497e90da3SNinad Palsule "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user", 18853e72c202SNinad Palsule "xyz.openbmc_project.User.Manager", "CreateUser", username, userGroups, 1886e01d0c36SEd Tanous roleId, enabled); 188797e90da3SNinad Palsule } 188897e90da3SNinad Palsule 18891ef4c342SEd Tanous inline void handleAccountCollectionPost( 18901ef4c342SEd Tanous App& app, const crow::Request& req, 18911ef4c342SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 18921ef4c342SEd Tanous { 18933ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 189445ca1b86SEd Tanous { 189545ca1b86SEd Tanous return; 189645ca1b86SEd Tanous } 18979712f8acSEd Tanous std::string username; 18989712f8acSEd Tanous std::string password; 1899e01d0c36SEd Tanous std::optional<std::string> roleIdJson; 1900e01d0c36SEd Tanous std::optional<bool> enabledJson; 19019ba73934SNinad Palsule std::optional<std::vector<std::string>> accountTypes; 1902*afc474aeSMyung Bae if (!json_util::readJsonPatch( // 1903*afc474aeSMyung Bae req, asyncResp->res, // 1904*afc474aeSMyung Bae "AccountTypes", accountTypes, // 1905*afc474aeSMyung Bae "Enabled", enabledJson, // 1906*afc474aeSMyung Bae "Password", password, // 1907*afc474aeSMyung Bae "RoleId", roleIdJson, // 1908*afc474aeSMyung Bae "UserName", username // 1909*afc474aeSMyung Bae )) 191004ae99ecSEd Tanous { 191104ae99ecSEd Tanous return; 191204ae99ecSEd Tanous } 191304ae99ecSEd Tanous 1914e01d0c36SEd Tanous std::string roleId = roleIdJson.value_or("User"); 1915e01d0c36SEd Tanous std::string priv = getPrivilegeFromRoleId(roleId); 191684e12cb7SAppaRao Puli if (priv.empty()) 191704ae99ecSEd Tanous { 1918e01d0c36SEd Tanous messages::propertyValueNotInList(asyncResp->res, roleId, "RoleId"); 191904ae99ecSEd Tanous return; 192004ae99ecSEd Tanous } 19219712f8acSEd Tanous roleId = priv; 192204ae99ecSEd Tanous 1923e01d0c36SEd Tanous bool enabled = enabledJson.value_or(true); 1924e01d0c36SEd Tanous 1925599c71d8SAyushi Smriti // Reading AllGroups property 19261e1e598dSJonathan Doman sdbusplus::asio::getProperty<std::vector<std::string>>( 19271ef4c342SEd Tanous *crow::connections::systemBus, "xyz.openbmc_project.User.Manager", 19281ef4c342SEd Tanous "/xyz/openbmc_project/user", "xyz.openbmc_project.User.Manager", 19291ef4c342SEd Tanous "AllGroups", 19309ba73934SNinad Palsule [asyncResp, username, password{std::move(password)}, roleId, enabled, 19319ba73934SNinad Palsule accountTypes](const boost::system::error_code& ec, 19321e1e598dSJonathan Doman const std::vector<std::string>& allGroupsList) { 1933599c71d8SAyushi Smriti if (ec) 1934599c71d8SAyushi Smriti { 1935a0735a4eSGunnar Mills BMCWEB_LOG_ERROR("D-Bus response error {}", ec); 1936599c71d8SAyushi Smriti messages::internalError(asyncResp->res); 1937599c71d8SAyushi Smriti return; 1938599c71d8SAyushi Smriti } 1939599c71d8SAyushi Smriti 19401e1e598dSJonathan Doman if (allGroupsList.empty()) 1941599c71d8SAyushi Smriti { 1942599c71d8SAyushi Smriti messages::internalError(asyncResp->res); 1943599c71d8SAyushi Smriti return; 1944599c71d8SAyushi Smriti } 1945599c71d8SAyushi Smriti 1946bd79bce8SPatrick Williams processAfterGetAllGroups(asyncResp, username, password, roleId, 1947bd79bce8SPatrick Williams enabled, accountTypes, allGroupsList); 19481e1e598dSJonathan Doman }); 19491ef4c342SEd Tanous } 1950b9b2e0b2SEd Tanous 19511ef4c342SEd Tanous inline void 19524c7d4d33SEd Tanous handleAccountHead(App& app, const crow::Request& req, 19536c51eab1SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 19544c7d4d33SEd Tanous const std::string& /*accountName*/) 19551ef4c342SEd Tanous { 19563ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 195745ca1b86SEd Tanous { 195845ca1b86SEd Tanous return; 195945ca1b86SEd Tanous } 19604c7d4d33SEd Tanous asyncResp->res.addHeader( 19614c7d4d33SEd Tanous boost::beast::http::field::link, 19624c7d4d33SEd Tanous "</redfish/v1/JsonSchemas/ManagerAccount/ManagerAccount.json>; rel=describedby"); 19634c7d4d33SEd Tanous } 1964afd369c6SJiaqing Zhao 19654c7d4d33SEd Tanous inline void 19664c7d4d33SEd Tanous handleAccountGet(App& app, const crow::Request& req, 19674c7d4d33SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 19684c7d4d33SEd Tanous const std::string& accountName) 19694c7d4d33SEd Tanous { 1970afd369c6SJiaqing Zhao if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 1971afd369c6SJiaqing Zhao { 1972afd369c6SJiaqing Zhao return; 1973afd369c6SJiaqing Zhao } 1974afd369c6SJiaqing Zhao asyncResp->res.addHeader( 1975afd369c6SJiaqing Zhao boost::beast::http::field::link, 1976afd369c6SJiaqing Zhao "</redfish/v1/JsonSchemas/ManagerAccount/ManagerAccount.json>; rel=describedby"); 1977afd369c6SJiaqing Zhao 197825b54dbaSEd Tanous if constexpr (BMCWEB_INSECURE_DISABLE_AUTH) 197925b54dbaSEd Tanous { 1980031514fbSJunLin Chen // If authentication is disabled, there are no user accounts 198125b54dbaSEd Tanous messages::resourceNotFound(asyncResp->res, "ManagerAccount", 198225b54dbaSEd Tanous accountName); 1983031514fbSJunLin Chen return; 198425b54dbaSEd Tanous } 1985afd369c6SJiaqing Zhao 1986031514fbSJunLin Chen if (req.session == nullptr) 1987031514fbSJunLin Chen { 1988031514fbSJunLin Chen messages::internalError(asyncResp->res); 1989031514fbSJunLin Chen return; 1990031514fbSJunLin Chen } 19916c51eab1SEd Tanous if (req.session->username != accountName) 1992b9b2e0b2SEd Tanous { 19936c51eab1SEd Tanous // At this point we've determined that the user is trying to 19941ef4c342SEd Tanous // modify a user that isn't them. We need to verify that they 19951ef4c342SEd Tanous // have permissions to modify other users, so re-run the auth 19961ef4c342SEd Tanous // check with the same permissions, minus ConfigureSelf. 19976c51eab1SEd Tanous Privileges effectiveUserPrivileges = 19983e72c202SNinad Palsule redfish::getUserPrivileges(*req.session); 19991ef4c342SEd Tanous Privileges requiredPermissionsToChangeNonSelf = {"ConfigureUsers", 20001ef4c342SEd Tanous "ConfigureManager"}; 20016c51eab1SEd Tanous if (!effectiveUserPrivileges.isSupersetOf( 20026c51eab1SEd Tanous requiredPermissionsToChangeNonSelf)) 2003900f9497SJoseph Reynolds { 200462598e31SEd Tanous BMCWEB_LOG_DEBUG("GET Account denied access"); 2005900f9497SJoseph Reynolds messages::insufficientPrivilege(asyncResp->res); 2006900f9497SJoseph Reynolds return; 2007900f9497SJoseph Reynolds } 2008900f9497SJoseph Reynolds } 2009900f9497SJoseph Reynolds 20105eb468daSGeorge Liu sdbusplus::message::object_path path("/xyz/openbmc_project/user"); 20115eb468daSGeorge Liu dbus::utility::getManagedObjects( 20125eb468daSGeorge Liu "xyz.openbmc_project.User.Manager", path, 20131ef4c342SEd Tanous [asyncResp, 20145e7e2dc5SEd Tanous accountName](const boost::system::error_code& ec, 2015711ac7a9SEd Tanous const dbus::utility::ManagedObjectType& users) { 2016b9b2e0b2SEd Tanous if (ec) 2017b9b2e0b2SEd Tanous { 2018f12894f8SJason M. Bills messages::internalError(asyncResp->res); 2019b9b2e0b2SEd Tanous return; 2020b9b2e0b2SEd Tanous } 20213544d2a7SEd Tanous const auto userIt = std::ranges::find_if( 202280f79a40SMichael Shen users, 202380f79a40SMichael Shen [accountName]( 2024b477fd44SP Dheeraj Srujan Kumar const std::pair<sdbusplus::message::object_path, 202580f79a40SMichael Shen dbus::utility::DBusInterfacesMap>& user) { 202655f79e6fSEd Tanous return accountName == user.first.filename(); 2027b477fd44SP Dheeraj Srujan Kumar }); 2028b9b2e0b2SEd Tanous 202984e12cb7SAppaRao Puli if (userIt == users.end()) 2030b9b2e0b2SEd Tanous { 2031002d39b4SEd Tanous messages::resourceNotFound(asyncResp->res, "ManagerAccount", 2032002d39b4SEd Tanous accountName); 203384e12cb7SAppaRao Puli return; 203484e12cb7SAppaRao Puli } 20354e68c45bSAyushi Smriti 20361476687dSEd Tanous asyncResp->res.jsonValue["@odata.type"] = 203758345856SAbhishek Patel "#ManagerAccount.v1_7_0.ManagerAccount"; 20381476687dSEd Tanous asyncResp->res.jsonValue["Name"] = "User Account"; 20391476687dSEd Tanous asyncResp->res.jsonValue["Description"] = "User Account"; 20401476687dSEd Tanous asyncResp->res.jsonValue["Password"] = nullptr; 204158345856SAbhishek Patel asyncResp->res.jsonValue["StrictAccountTypes"] = true; 20424e68c45bSAyushi Smriti 204384e12cb7SAppaRao Puli for (const auto& interface : userIt->second) 204465b0dc32SEd Tanous { 2045002d39b4SEd Tanous if (interface.first == "xyz.openbmc_project.User.Attributes") 204665b0dc32SEd Tanous { 204765b0dc32SEd Tanous for (const auto& property : interface.second) 204865b0dc32SEd Tanous { 204965b0dc32SEd Tanous if (property.first == "UserEnabled") 205065b0dc32SEd Tanous { 205165b0dc32SEd Tanous const bool* userEnabled = 2052abf2add6SEd Tanous std::get_if<bool>(&property.second); 205365b0dc32SEd Tanous if (userEnabled == nullptr) 205465b0dc32SEd Tanous { 205562598e31SEd Tanous BMCWEB_LOG_ERROR("UserEnabled wasn't a bool"); 205684e12cb7SAppaRao Puli messages::internalError(asyncResp->res); 205784e12cb7SAppaRao Puli return; 205865b0dc32SEd Tanous } 2059002d39b4SEd Tanous asyncResp->res.jsonValue["Enabled"] = *userEnabled; 206065b0dc32SEd Tanous } 2061002d39b4SEd Tanous else if (property.first == "UserLockedForFailedAttempt") 206265b0dc32SEd Tanous { 206365b0dc32SEd Tanous const bool* userLocked = 2064abf2add6SEd Tanous std::get_if<bool>(&property.second); 206565b0dc32SEd Tanous if (userLocked == nullptr) 206665b0dc32SEd Tanous { 206762598e31SEd Tanous BMCWEB_LOG_ERROR("UserLockedForF" 206884e12cb7SAppaRao Puli "ailedAttempt " 206962598e31SEd Tanous "wasn't a bool"); 207084e12cb7SAppaRao Puli messages::internalError(asyncResp->res); 207184e12cb7SAppaRao Puli return; 207265b0dc32SEd Tanous } 2073002d39b4SEd Tanous asyncResp->res.jsonValue["Locked"] = *userLocked; 207420fa6a2cSEd Tanous nlohmann::json::array_t allowed; 207520fa6a2cSEd Tanous // can only unlock accounts 207620fa6a2cSEd Tanous allowed.emplace_back("false"); 2077002d39b4SEd Tanous asyncResp->res 207820fa6a2cSEd Tanous .jsonValue["Locked@Redfish.AllowableValues"] = 207920fa6a2cSEd Tanous std::move(allowed); 208065b0dc32SEd Tanous } 208184e12cb7SAppaRao Puli else if (property.first == "UserPrivilege") 208284e12cb7SAppaRao Puli { 208354fc587aSNagaraju Goruganti const std::string* userPrivPtr = 2084002d39b4SEd Tanous std::get_if<std::string>(&property.second); 208554fc587aSNagaraju Goruganti if (userPrivPtr == nullptr) 208684e12cb7SAppaRao Puli { 208762598e31SEd Tanous BMCWEB_LOG_ERROR("UserPrivilege wasn't a " 208862598e31SEd Tanous "string"); 208984e12cb7SAppaRao Puli messages::internalError(asyncResp->res); 209084e12cb7SAppaRao Puli return; 209184e12cb7SAppaRao Puli } 2092bd79bce8SPatrick Williams std::string role = 2093bd79bce8SPatrick Williams getRoleIdFromPrivilege(*userPrivPtr); 209454fc587aSNagaraju Goruganti if (role.empty()) 209584e12cb7SAppaRao Puli { 209662598e31SEd Tanous BMCWEB_LOG_ERROR("Invalid user role"); 209784e12cb7SAppaRao Puli messages::internalError(asyncResp->res); 209884e12cb7SAppaRao Puli return; 209984e12cb7SAppaRao Puli } 210054fc587aSNagaraju Goruganti asyncResp->res.jsonValue["RoleId"] = role; 210184e12cb7SAppaRao Puli 21021476687dSEd Tanous nlohmann::json& roleEntry = 2103002d39b4SEd Tanous asyncResp->res.jsonValue["Links"]["Role"]; 21043b32780dSEd Tanous roleEntry["@odata.id"] = boost::urls::format( 21053b32780dSEd Tanous "/redfish/v1/AccountService/Roles/{}", role); 210684e12cb7SAppaRao Puli } 2107002d39b4SEd Tanous else if (property.first == "UserPasswordExpired") 21083bf4e632SJoseph Reynolds { 21093bf4e632SJoseph Reynolds const bool* userPasswordExpired = 21103bf4e632SJoseph Reynolds std::get_if<bool>(&property.second); 21113bf4e632SJoseph Reynolds if (userPasswordExpired == nullptr) 21123bf4e632SJoseph Reynolds { 211362598e31SEd Tanous BMCWEB_LOG_ERROR( 211462598e31SEd Tanous "UserPasswordExpired wasn't a bool"); 21153bf4e632SJoseph Reynolds messages::internalError(asyncResp->res); 21163bf4e632SJoseph Reynolds return; 21173bf4e632SJoseph Reynolds } 2118002d39b4SEd Tanous asyncResp->res.jsonValue["PasswordChangeRequired"] = 21193bf4e632SJoseph Reynolds *userPasswordExpired; 21203bf4e632SJoseph Reynolds } 2121c7229815SAbhishek Patel else if (property.first == "UserGroups") 2122c7229815SAbhishek Patel { 2123c7229815SAbhishek Patel const std::vector<std::string>* userGroups = 2124c7229815SAbhishek Patel std::get_if<std::vector<std::string>>( 2125c7229815SAbhishek Patel &property.second); 2126c7229815SAbhishek Patel if (userGroups == nullptr) 2127c7229815SAbhishek Patel { 212862598e31SEd Tanous BMCWEB_LOG_ERROR( 212962598e31SEd Tanous "userGroups wasn't a string vector"); 2130c7229815SAbhishek Patel messages::internalError(asyncResp->res); 2131c7229815SAbhishek Patel return; 2132c7229815SAbhishek Patel } 2133bd79bce8SPatrick Williams if (!translateUserGroup(*userGroups, 2134bd79bce8SPatrick Williams asyncResp->res)) 2135c7229815SAbhishek Patel { 213662598e31SEd Tanous BMCWEB_LOG_ERROR("userGroups mapping failed"); 2137c7229815SAbhishek Patel messages::internalError(asyncResp->res); 2138c7229815SAbhishek Patel return; 2139c7229815SAbhishek Patel } 2140c7229815SAbhishek Patel } 214165b0dc32SEd Tanous } 214265b0dc32SEd Tanous } 214365b0dc32SEd Tanous } 214465b0dc32SEd Tanous 21453b32780dSEd Tanous asyncResp->res.jsonValue["@odata.id"] = boost::urls::format( 21463b32780dSEd Tanous "/redfish/v1/AccountService/Accounts/{}", accountName); 2147b9b2e0b2SEd Tanous asyncResp->res.jsonValue["Id"] = accountName; 2148b9b2e0b2SEd Tanous asyncResp->res.jsonValue["UserName"] = accountName; 21495eb468daSGeorge Liu }); 21501ef4c342SEd Tanous } 2151a840879dSEd Tanous 21521ef4c342SEd Tanous inline void 215320fc307fSGunnar Mills handleAccountDelete(App& app, const crow::Request& req, 21546c51eab1SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 21551ef4c342SEd Tanous const std::string& username) 21561ef4c342SEd Tanous { 21573ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 215845ca1b86SEd Tanous { 215945ca1b86SEd Tanous return; 216045ca1b86SEd Tanous } 21611ef4c342SEd Tanous 216225b54dbaSEd Tanous if constexpr (BMCWEB_INSECURE_DISABLE_AUTH) 216325b54dbaSEd Tanous { 2164031514fbSJunLin Chen // If authentication is disabled, there are no user accounts 2165d8a5d5d8SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "ManagerAccount", username); 2166031514fbSJunLin Chen return; 216725b54dbaSEd Tanous } 21681ef4c342SEd Tanous sdbusplus::message::object_path tempObjPath(rootUserDbusPath); 21691ef4c342SEd Tanous tempObjPath /= username; 21701ef4c342SEd Tanous const std::string userPath(tempObjPath); 21711ef4c342SEd Tanous 21721ef4c342SEd Tanous crow::connections::systemBus->async_method_call( 21735e7e2dc5SEd Tanous [asyncResp, username](const boost::system::error_code& ec) { 21741ef4c342SEd Tanous if (ec) 21751ef4c342SEd Tanous { 2176d8a5d5d8SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "ManagerAccount", 21771ef4c342SEd Tanous username); 21781ef4c342SEd Tanous return; 21791ef4c342SEd Tanous } 21801ef4c342SEd Tanous 21811ef4c342SEd Tanous messages::accountRemoved(asyncResp->res); 21821ef4c342SEd Tanous }, 21831ef4c342SEd Tanous "xyz.openbmc_project.User.Manager", userPath, 21841ef4c342SEd Tanous "xyz.openbmc_project.Object.Delete", "Delete"); 21851ef4c342SEd Tanous } 21861ef4c342SEd Tanous 21871ef4c342SEd Tanous inline void 21881ef4c342SEd Tanous handleAccountPatch(App& app, const crow::Request& req, 21891ef4c342SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 21901ef4c342SEd Tanous const std::string& username) 21911ef4c342SEd Tanous { 21921ef4c342SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 21931ef4c342SEd Tanous { 21941ef4c342SEd Tanous return; 21951ef4c342SEd Tanous } 219625b54dbaSEd Tanous if constexpr (BMCWEB_INSECURE_DISABLE_AUTH) 219725b54dbaSEd Tanous { 21981ef4c342SEd Tanous // If authentication is disabled, there are no user accounts 2199d8a5d5d8SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "ManagerAccount", username); 22001ef4c342SEd Tanous return; 220125b54dbaSEd Tanous } 2202a24526dcSEd Tanous std::optional<std::string> newUserName; 2203a24526dcSEd Tanous std::optional<std::string> password; 2204a24526dcSEd Tanous std::optional<bool> enabled; 2205a24526dcSEd Tanous std::optional<std::string> roleId; 220624c8542dSRatan Gupta std::optional<bool> locked; 220758345856SAbhishek Patel std::optional<std::vector<std::string>> accountTypes; 220858345856SAbhishek Patel 2209031514fbSJunLin Chen if (req.session == nullptr) 2210031514fbSJunLin Chen { 2211031514fbSJunLin Chen messages::internalError(asyncResp->res); 2212031514fbSJunLin Chen return; 2213031514fbSJunLin Chen } 2214031514fbSJunLin Chen 22152b9c1dfeSEd Tanous bool userSelf = (username == req.session->username); 22162b9c1dfeSEd Tanous 2217e9cc5172SEd Tanous Privileges effectiveUserPrivileges = 22183e72c202SNinad Palsule redfish::getUserPrivileges(*req.session); 2219e9cc5172SEd Tanous Privileges configureUsers = {"ConfigureUsers"}; 2220e9cc5172SEd Tanous bool userHasConfigureUsers = 2221e9cc5172SEd Tanous effectiveUserPrivileges.isSupersetOf(configureUsers); 2222e9cc5172SEd Tanous if (userHasConfigureUsers) 2223e9cc5172SEd Tanous { 2224e9cc5172SEd Tanous // Users with ConfigureUsers can modify for all users 2225*afc474aeSMyung Bae if (!json_util::readJsonPatch( // 2226*afc474aeSMyung Bae req, asyncResp->res, // 2227*afc474aeSMyung Bae "AccountTypes", accountTypes, // 2228*afc474aeSMyung Bae "Enabled", enabled, // 2229*afc474aeSMyung Bae "Locked", locked, // 2230*afc474aeSMyung Bae "Password", password, // 2231*afc474aeSMyung Bae "RoleId", roleId, // 2232*afc474aeSMyung Bae "UserName", newUserName // 2233*afc474aeSMyung Bae )) 2234a840879dSEd Tanous { 2235a840879dSEd Tanous return; 2236a840879dSEd Tanous } 2237e9cc5172SEd Tanous } 2238e9cc5172SEd Tanous else 2239900f9497SJoseph Reynolds { 2240e9cc5172SEd Tanous // ConfigureSelf accounts can only modify their own account 224158345856SAbhishek Patel if (!userSelf) 2242900f9497SJoseph Reynolds { 2243900f9497SJoseph Reynolds messages::insufficientPrivilege(asyncResp->res); 2244900f9497SJoseph Reynolds return; 2245900f9497SJoseph Reynolds } 2246031514fbSJunLin Chen 2247e9cc5172SEd Tanous // ConfigureSelf accounts can only modify their password 22481ef4c342SEd Tanous if (!json_util::readJsonPatch(req, asyncResp->res, "Password", 22491ef4c342SEd Tanous password)) 2250e9cc5172SEd Tanous { 2251e9cc5172SEd Tanous return; 2252e9cc5172SEd Tanous } 2253900f9497SJoseph Reynolds } 2254900f9497SJoseph Reynolds 225566b5ca76Sjayaprakash Mutyala // if user name is not provided in the patch method or if it 22566c51eab1SEd Tanous // matches the user name in the URI, then we are treating it as 22576c51eab1SEd Tanous // updating user properties other then username. If username 22586c51eab1SEd Tanous // provided doesn't match the URI, then we are treating this as 22596c51eab1SEd Tanous // user rename request. 226066b5ca76Sjayaprakash Mutyala if (!newUserName || (newUserName.value() == username)) 2261a840879dSEd Tanous { 22621ef4c342SEd Tanous updateUserProperties(asyncResp, username, password, enabled, roleId, 2263e518ef32SRavi Teja locked, accountTypes, userSelf, req.session); 226484e12cb7SAppaRao Puli return; 226584e12cb7SAppaRao Puli } 226684e12cb7SAppaRao Puli crow::connections::systemBus->async_method_call( 22676c51eab1SEd Tanous [asyncResp, username, password(std::move(password)), 22681ef4c342SEd Tanous roleId(std::move(roleId)), enabled, newUser{std::string(*newUserName)}, 2269e518ef32SRavi Teja locked, userSelf, req, accountTypes(std::move(accountTypes))]( 2270e81de512SEd Tanous const boost::system::error_code& ec, sdbusplus::message_t& m) { 227184e12cb7SAppaRao Puli if (ec) 227284e12cb7SAppaRao Puli { 2273002d39b4SEd Tanous userErrorMessageHandler(m.get_error(), asyncResp, newUser, 2274002d39b4SEd Tanous username); 2275a840879dSEd Tanous return; 2276a840879dSEd Tanous } 2277a840879dSEd Tanous 2278002d39b4SEd Tanous updateUserProperties(asyncResp, newUser, password, enabled, roleId, 2279e518ef32SRavi Teja locked, accountTypes, userSelf, req.session); 228084e12cb7SAppaRao Puli }, 22811ef4c342SEd Tanous "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user", 228284e12cb7SAppaRao Puli "xyz.openbmc_project.User.Manager", "RenameUser", username, 228384e12cb7SAppaRao Puli *newUserName); 22841ef4c342SEd Tanous } 22851ef4c342SEd Tanous 22861ef4c342SEd Tanous inline void requestAccountServiceRoutes(App& app) 22871ef4c342SEd Tanous { 22881ef4c342SEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/AccountService/") 22894c7d4d33SEd Tanous .privileges(redfish::privileges::headAccountService) 22904c7d4d33SEd Tanous .methods(boost::beast::http::verb::head)( 22914c7d4d33SEd Tanous std::bind_front(handleAccountServiceHead, std::ref(app))); 22924c7d4d33SEd Tanous 22934c7d4d33SEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/AccountService/") 22941ef4c342SEd Tanous .privileges(redfish::privileges::getAccountService) 22951ef4c342SEd Tanous .methods(boost::beast::http::verb::get)( 22961ef4c342SEd Tanous std::bind_front(handleAccountServiceGet, std::ref(app))); 22971ef4c342SEd Tanous 22981ef4c342SEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/AccountService/") 22991ef4c342SEd Tanous .privileges(redfish::privileges::patchAccountService) 23001ef4c342SEd Tanous .methods(boost::beast::http::verb::patch)( 23011ef4c342SEd Tanous std::bind_front(handleAccountServicePatch, std::ref(app))); 23021ef4c342SEd Tanous 23031aa375b8SEd Tanous BMCWEB_ROUTE( 23041aa375b8SEd Tanous app, 2305e9f12014SEd Tanous "/redfish/v1/AccountService/MultiFactorAuth/ClientCertificate/Certificates/") 23061aa375b8SEd Tanous .privileges(redfish::privileges::headCertificateCollection) 23071aa375b8SEd Tanous .methods(boost::beast::http::verb::head)(std::bind_front( 23081aa375b8SEd Tanous handleAccountServiceClientCertificatesHead, std::ref(app))); 23091aa375b8SEd Tanous 23101aa375b8SEd Tanous BMCWEB_ROUTE( 23111aa375b8SEd Tanous app, 2312e9f12014SEd Tanous "/redfish/v1/AccountService/MultiFactorAuth/ClientCertificate/Certificates/") 23131aa375b8SEd Tanous .privileges(redfish::privileges::getCertificateCollection) 23141aa375b8SEd Tanous .methods(boost::beast::http::verb::get)(std::bind_front( 23151aa375b8SEd Tanous handleAccountServiceClientCertificatesGet, std::ref(app))); 23161aa375b8SEd Tanous 23171aa375b8SEd Tanous BMCWEB_ROUTE( 23181aa375b8SEd Tanous app, 2319e9f12014SEd Tanous "/redfish/v1/AccountService/MultiFactorAuth/ClientCertificate/Certificates/<str>/") 23201aa375b8SEd Tanous .privileges(redfish::privileges::headCertificate) 23211aa375b8SEd Tanous .methods(boost::beast::http::verb::head)(std::bind_front( 23221aa375b8SEd Tanous handleAccountServiceClientCertificatesInstanceHead, std::ref(app))); 23231aa375b8SEd Tanous 23241aa375b8SEd Tanous BMCWEB_ROUTE( 23251aa375b8SEd Tanous app, 23261aa375b8SEd Tanous "/redfish/v1/AccountService/MultiFactorAuth/ClientCertificate/Certificates/<str>/") 23271aa375b8SEd Tanous .privileges(redfish::privileges::getCertificate) 23281aa375b8SEd Tanous .methods(boost::beast::http::verb::get)(std::bind_front( 23291aa375b8SEd Tanous handleAccountServiceClientCertificatesInstanceGet, std::ref(app))); 23301aa375b8SEd Tanous 23311ef4c342SEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/") 23324c7d4d33SEd Tanous .privileges(redfish::privileges::headManagerAccountCollection) 23334c7d4d33SEd Tanous .methods(boost::beast::http::verb::head)( 23344c7d4d33SEd Tanous std::bind_front(handleAccountCollectionHead, std::ref(app))); 23354c7d4d33SEd Tanous 23364c7d4d33SEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/") 23371ef4c342SEd Tanous .privileges(redfish::privileges::getManagerAccountCollection) 23381ef4c342SEd Tanous .methods(boost::beast::http::verb::get)( 23391ef4c342SEd Tanous std::bind_front(handleAccountCollectionGet, std::ref(app))); 23401ef4c342SEd Tanous 23411ef4c342SEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/") 23421ef4c342SEd Tanous .privileges(redfish::privileges::postManagerAccountCollection) 23431ef4c342SEd Tanous .methods(boost::beast::http::verb::post)( 23441ef4c342SEd Tanous std::bind_front(handleAccountCollectionPost, std::ref(app))); 23451ef4c342SEd Tanous 23461ef4c342SEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/<str>/") 23474c7d4d33SEd Tanous .privileges(redfish::privileges::headManagerAccount) 23484c7d4d33SEd Tanous .methods(boost::beast::http::verb::head)( 23494c7d4d33SEd Tanous std::bind_front(handleAccountHead, std::ref(app))); 23504c7d4d33SEd Tanous 23514c7d4d33SEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/<str>/") 23521ef4c342SEd Tanous .privileges(redfish::privileges::getManagerAccount) 23531ef4c342SEd Tanous .methods(boost::beast::http::verb::get)( 23541ef4c342SEd Tanous std::bind_front(handleAccountGet, std::ref(app))); 23551ef4c342SEd Tanous 23561ef4c342SEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/<str>/") 23571ef4c342SEd Tanous // TODO this privilege should be using the generated endpoints, but 23581ef4c342SEd Tanous // because of the special handling of ConfigureSelf, it's not able to 23591ef4c342SEd Tanous // yet 23601ef4c342SEd Tanous .privileges({{"ConfigureUsers"}, {"ConfigureSelf"}}) 23611ef4c342SEd Tanous .methods(boost::beast::http::verb::patch)( 23621ef4c342SEd Tanous std::bind_front(handleAccountPatch, std::ref(app))); 236384e12cb7SAppaRao Puli 23646c51eab1SEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/<str>/") 2365ed398213SEd Tanous .privileges(redfish::privileges::deleteManagerAccount) 23666c51eab1SEd Tanous .methods(boost::beast::http::verb::delete_)( 236720fc307fSGunnar Mills std::bind_front(handleAccountDelete, std::ref(app))); 236806e086d9SEd Tanous } 236988d16c9aSLewanczyk, Dawid 237088d16c9aSLewanczyk, Dawid } // namespace redfish 2371