188d16c9aSLewanczyk, Dawid /* 288d16c9aSLewanczyk, Dawid // Copyright (c) 2018 Intel Corporation 388d16c9aSLewanczyk, Dawid // 488d16c9aSLewanczyk, Dawid // Licensed under the Apache License, Version 2.0 (the "License"); 588d16c9aSLewanczyk, Dawid // you may not use this file except in compliance with the License. 688d16c9aSLewanczyk, Dawid // You may obtain a copy of the License at 788d16c9aSLewanczyk, Dawid // 888d16c9aSLewanczyk, Dawid // http://www.apache.org/licenses/LICENSE-2.0 988d16c9aSLewanczyk, Dawid // 1088d16c9aSLewanczyk, Dawid // Unless required by applicable law or agreed to in writing, software 1188d16c9aSLewanczyk, Dawid // distributed under the License is distributed on an "AS IS" BASIS, 1288d16c9aSLewanczyk, Dawid // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1388d16c9aSLewanczyk, Dawid // See the License for the specific language governing permissions and 1488d16c9aSLewanczyk, Dawid // limitations under the License. 1588d16c9aSLewanczyk, Dawid */ 1688d16c9aSLewanczyk, Dawid #pragma once 1788d16c9aSLewanczyk, Dawid #include "node.hpp" 1888d16c9aSLewanczyk, Dawid 1924c8542dSRatan Gupta #include <dbus_utility.hpp> 2065b0dc32SEd Tanous #include <error_messages.hpp> 21b9b2e0b2SEd Tanous #include <openbmc_dbus_rest.hpp> 22a840879dSEd Tanous #include <utils/json_utils.hpp> 23abf2add6SEd Tanous #include <variant> 24b9b2e0b2SEd Tanous 251abe55efSEd Tanous namespace redfish 261abe55efSEd Tanous { 2788d16c9aSLewanczyk, Dawid 286973a582SRatan Gupta constexpr const char* ldapConfigObject = 296973a582SRatan Gupta "/xyz/openbmc_project/user/ldap/openldap"; 30ab828d7cSRatan Gupta constexpr const char* ADConfigObject = 31ab828d7cSRatan Gupta "/xyz/openbmc_project/user/ldap/active_directory"; 32ab828d7cSRatan Gupta 336973a582SRatan Gupta constexpr const char* ldapRootObject = "/xyz/openbmc_project/user/ldap"; 346973a582SRatan Gupta constexpr const char* ldapDbusService = "xyz.openbmc_project.Ldap.Config"; 356973a582SRatan Gupta constexpr const char* ldapConfigInterface = 366973a582SRatan Gupta "xyz.openbmc_project.User.Ldap.Config"; 376973a582SRatan Gupta constexpr const char* ldapCreateInterface = 386973a582SRatan Gupta "xyz.openbmc_project.User.Ldap.Create"; 396973a582SRatan Gupta constexpr const char* ldapEnableInterface = "xyz.openbmc_project.Object.Enable"; 4006785244SRatan Gupta constexpr const char* ldapPrivMapperInterface = 4106785244SRatan Gupta "xyz.openbmc_project.User.PrivilegeMapper"; 426973a582SRatan Gupta constexpr const char* dbusObjManagerIntf = "org.freedesktop.DBus.ObjectManager"; 436973a582SRatan Gupta constexpr const char* propertyInterface = "org.freedesktop.DBus.Properties"; 446973a582SRatan Gupta constexpr const char* mapperBusName = "xyz.openbmc_project.ObjectMapper"; 456973a582SRatan Gupta constexpr const char* mapperObjectPath = "/xyz/openbmc_project/object_mapper"; 466973a582SRatan Gupta constexpr const char* mapperIntf = "xyz.openbmc_project.ObjectMapper"; 476973a582SRatan Gupta 4854fc587aSNagaraju Goruganti struct LDAPRoleMapData 4954fc587aSNagaraju Goruganti { 5054fc587aSNagaraju Goruganti std::string groupName; 5154fc587aSNagaraju Goruganti std::string privilege; 5254fc587aSNagaraju Goruganti }; 5354fc587aSNagaraju Goruganti 546973a582SRatan Gupta struct LDAPConfigData 556973a582SRatan Gupta { 566973a582SRatan Gupta std::string uri{}; 576973a582SRatan Gupta std::string bindDN{}; 586973a582SRatan Gupta std::string baseDN{}; 596973a582SRatan Gupta std::string searchScope{}; 606973a582SRatan Gupta std::string serverType{}; 616973a582SRatan Gupta bool serviceEnabled = false; 626973a582SRatan Gupta std::string userNameAttribute{}; 636973a582SRatan Gupta std::string groupAttribute{}; 6454fc587aSNagaraju Goruganti std::vector<std::pair<std::string, LDAPRoleMapData>> groupRoleList; 656973a582SRatan Gupta }; 666973a582SRatan Gupta 67b9b2e0b2SEd Tanous using ManagedObjectType = std::vector<std::pair< 68b9b2e0b2SEd Tanous sdbusplus::message::object_path, 69b9b2e0b2SEd Tanous boost::container::flat_map< 70abf2add6SEd Tanous std::string, boost::container::flat_map< 71abf2add6SEd Tanous std::string, std::variant<bool, std::string>>>>>; 726973a582SRatan Gupta using GetObjectType = 736973a582SRatan Gupta std::vector<std::pair<std::string, std::vector<std::string>>>; 7484e12cb7SAppaRao Puli 7554fc587aSNagaraju Goruganti inline std::string getRoleIdFromPrivilege(std::string_view role) 7684e12cb7SAppaRao Puli { 7784e12cb7SAppaRao Puli if (role == "priv-admin") 7884e12cb7SAppaRao Puli { 7984e12cb7SAppaRao Puli return "Administrator"; 8084e12cb7SAppaRao Puli } 8184e12cb7SAppaRao Puli else if (role == "priv-callback") 8284e12cb7SAppaRao Puli { 8384e12cb7SAppaRao Puli return "Callback"; 8484e12cb7SAppaRao Puli } 8584e12cb7SAppaRao Puli else if (role == "priv-user") 8684e12cb7SAppaRao Puli { 87c80fee55SAppaRao Puli return "ReadOnly"; 8884e12cb7SAppaRao Puli } 8984e12cb7SAppaRao Puli else if (role == "priv-operator") 9084e12cb7SAppaRao Puli { 9184e12cb7SAppaRao Puli return "Operator"; 9284e12cb7SAppaRao Puli } 9384e12cb7SAppaRao Puli return ""; 9484e12cb7SAppaRao Puli } 9554fc587aSNagaraju Goruganti inline std::string getPrivilegeFromRoleId(std::string_view role) 9684e12cb7SAppaRao Puli { 9784e12cb7SAppaRao Puli if (role == "Administrator") 9884e12cb7SAppaRao Puli { 9984e12cb7SAppaRao Puli return "priv-admin"; 10084e12cb7SAppaRao Puli } 10184e12cb7SAppaRao Puli else if (role == "Callback") 10284e12cb7SAppaRao Puli { 10384e12cb7SAppaRao Puli return "priv-callback"; 10484e12cb7SAppaRao Puli } 105c80fee55SAppaRao Puli else if (role == "ReadOnly") 10684e12cb7SAppaRao Puli { 10784e12cb7SAppaRao Puli return "priv-user"; 10884e12cb7SAppaRao Puli } 10984e12cb7SAppaRao Puli else if (role == "Operator") 11084e12cb7SAppaRao Puli { 11184e12cb7SAppaRao Puli return "priv-operator"; 11284e12cb7SAppaRao Puli } 11384e12cb7SAppaRao Puli return ""; 11484e12cb7SAppaRao Puli } 115b9b2e0b2SEd Tanous 116*66b5ca76Sjayaprakash Mutyala void userErrorMessageHandler(const sd_bus_error* e, 117*66b5ca76Sjayaprakash Mutyala std::shared_ptr<AsyncResp> asyncResp, 118*66b5ca76Sjayaprakash Mutyala const std::string& newUser, 119*66b5ca76Sjayaprakash Mutyala const std::string& username) 120*66b5ca76Sjayaprakash Mutyala { 121*66b5ca76Sjayaprakash Mutyala const char* errorMessage = e->name; 122*66b5ca76Sjayaprakash Mutyala if (e == nullptr) 123*66b5ca76Sjayaprakash Mutyala { 124*66b5ca76Sjayaprakash Mutyala messages::internalError(asyncResp->res); 125*66b5ca76Sjayaprakash Mutyala return; 126*66b5ca76Sjayaprakash Mutyala } 127*66b5ca76Sjayaprakash Mutyala 128*66b5ca76Sjayaprakash Mutyala if (strcmp(errorMessage, 129*66b5ca76Sjayaprakash Mutyala "xyz.openbmc_project.User.Common.Error.UserNameExists") == 0) 130*66b5ca76Sjayaprakash Mutyala { 131*66b5ca76Sjayaprakash Mutyala messages::resourceAlreadyExists(asyncResp->res, 132*66b5ca76Sjayaprakash Mutyala "#ManagerAccount.v1_0_3.ManagerAccount", 133*66b5ca76Sjayaprakash Mutyala "UserName", newUser); 134*66b5ca76Sjayaprakash Mutyala } 135*66b5ca76Sjayaprakash Mutyala else if (strcmp(errorMessage, "xyz.openbmc_project.User.Common.Error." 136*66b5ca76Sjayaprakash Mutyala "UserNameDoesNotExist") == 0) 137*66b5ca76Sjayaprakash Mutyala { 138*66b5ca76Sjayaprakash Mutyala messages::resourceNotFound( 139*66b5ca76Sjayaprakash Mutyala asyncResp->res, "#ManagerAccount.v1_0_3.ManagerAccount", username); 140*66b5ca76Sjayaprakash Mutyala } 141*66b5ca76Sjayaprakash Mutyala else if (strcmp(errorMessage, 142*66b5ca76Sjayaprakash Mutyala "xyz.openbmc_project.Common.Error.InvalidArgument") == 0) 143*66b5ca76Sjayaprakash Mutyala { 144*66b5ca76Sjayaprakash Mutyala messages::propertyValueFormatError(asyncResp->res, newUser, "UserName"); 145*66b5ca76Sjayaprakash Mutyala } 146*66b5ca76Sjayaprakash Mutyala else if (strcmp(errorMessage, 147*66b5ca76Sjayaprakash Mutyala "xyz.openbmc_project.User.Common.Error.NoResource") == 0) 148*66b5ca76Sjayaprakash Mutyala { 149*66b5ca76Sjayaprakash Mutyala messages::createLimitReachedForResource(asyncResp->res); 150*66b5ca76Sjayaprakash Mutyala } 151*66b5ca76Sjayaprakash Mutyala else if (strcmp(errorMessage, "xyz.openbmc_project.User.Common.Error." 152*66b5ca76Sjayaprakash Mutyala "UserNameGroupFail") == 0) 153*66b5ca76Sjayaprakash Mutyala { 154*66b5ca76Sjayaprakash Mutyala messages::propertyValueFormatError(asyncResp->res, newUser, "UserName"); 155*66b5ca76Sjayaprakash Mutyala } 156*66b5ca76Sjayaprakash Mutyala else 157*66b5ca76Sjayaprakash Mutyala { 158*66b5ca76Sjayaprakash Mutyala messages::internalError(asyncResp->res); 159*66b5ca76Sjayaprakash Mutyala } 160*66b5ca76Sjayaprakash Mutyala 161*66b5ca76Sjayaprakash Mutyala return; 162*66b5ca76Sjayaprakash Mutyala } 163*66b5ca76Sjayaprakash Mutyala 1646973a582SRatan Gupta void parseLDAPConfigData(nlohmann::json& json_response, 165ab828d7cSRatan Gupta const LDAPConfigData& confData, 166ab828d7cSRatan Gupta const std::string& ldapType) 1676973a582SRatan Gupta { 168ab828d7cSRatan Gupta std::string service = 169ab828d7cSRatan Gupta (ldapType == "LDAP") ? "LDAPService" : "ActiveDirectoryService"; 17037cce918SMarri Devender Rao nlohmann::json ldap = { 1716973a582SRatan Gupta {"AccountProviderType", service}, 1726973a582SRatan Gupta {"ServiceEnabled", confData.serviceEnabled}, 1736973a582SRatan Gupta {"ServiceAddresses", nlohmann::json::array({confData.uri})}, 1746973a582SRatan Gupta {"Authentication", 1756973a582SRatan Gupta {{"AuthenticationType", "UsernameAndPassword"}, 1766973a582SRatan Gupta {"Username", confData.bindDN}, 1776973a582SRatan Gupta {"Password", nullptr}}}, 1786973a582SRatan Gupta {"LDAPService", 1796973a582SRatan Gupta {{"SearchSettings", 1806973a582SRatan Gupta {{"BaseDistinguishedNames", 1816973a582SRatan Gupta nlohmann::json::array({confData.baseDN})}, 1826973a582SRatan Gupta {"UsernameAttribute", confData.userNameAttribute}, 1836973a582SRatan Gupta {"GroupsAttribute", confData.groupAttribute}}}}}, 1846973a582SRatan Gupta }; 18554fc587aSNagaraju Goruganti 18637cce918SMarri Devender Rao json_response[ldapType].update(std::move(ldap)); 18754fc587aSNagaraju Goruganti 18854fc587aSNagaraju Goruganti nlohmann::json& roleMapArray = json_response[ldapType]["RemoteRoleMapping"]; 18954fc587aSNagaraju Goruganti roleMapArray = nlohmann::json::array(); 19054fc587aSNagaraju Goruganti for (auto& obj : confData.groupRoleList) 19154fc587aSNagaraju Goruganti { 19254fc587aSNagaraju Goruganti BMCWEB_LOG_DEBUG << "Pushing the data groupName=" 19354fc587aSNagaraju Goruganti << obj.second.groupName << "\n"; 19454fc587aSNagaraju Goruganti roleMapArray.push_back( 19554fc587aSNagaraju Goruganti {nlohmann::json::array({"RemoteGroup", obj.second.groupName}), 19654fc587aSNagaraju Goruganti nlohmann::json::array( 19754fc587aSNagaraju Goruganti {"LocalRole", getRoleIdFromPrivilege(obj.second.privilege)})}); 19854fc587aSNagaraju Goruganti } 1996973a582SRatan Gupta } 2006973a582SRatan Gupta 2016973a582SRatan Gupta /** 20206785244SRatan Gupta * @brief validates given JSON input and then calls appropriate method to 20306785244SRatan Gupta * create, to delete or to set Rolemapping object based on the given input. 20406785244SRatan Gupta * 20506785244SRatan Gupta */ 20606785244SRatan Gupta static void handleRoleMapPatch( 20706785244SRatan Gupta const std::shared_ptr<AsyncResp>& asyncResp, 20806785244SRatan Gupta const std::vector<std::pair<std::string, LDAPRoleMapData>>& roleMapObjData, 20906785244SRatan Gupta const std::string& serverType, std::vector<nlohmann::json>& input) 21006785244SRatan Gupta { 21106785244SRatan Gupta for (size_t index = 0; index < input.size(); index++) 21206785244SRatan Gupta { 21306785244SRatan Gupta nlohmann::json& thisJson = input[index]; 21406785244SRatan Gupta 21506785244SRatan Gupta if (thisJson.is_null()) 21606785244SRatan Gupta { 21706785244SRatan Gupta // delete the existing object 21806785244SRatan Gupta if (index < roleMapObjData.size()) 21906785244SRatan Gupta { 22006785244SRatan Gupta crow::connections::systemBus->async_method_call( 22106785244SRatan Gupta [asyncResp, roleMapObjData, serverType, 22206785244SRatan Gupta index](const boost::system::error_code ec) { 22306785244SRatan Gupta if (ec) 22406785244SRatan Gupta { 22506785244SRatan Gupta BMCWEB_LOG_ERROR << "DBUS response error: " << ec; 22606785244SRatan Gupta messages::internalError(asyncResp->res); 22706785244SRatan Gupta return; 22806785244SRatan Gupta } 22906785244SRatan Gupta asyncResp->res 23006785244SRatan Gupta .jsonValue[serverType]["RemoteRoleMapping"][index] = 23106785244SRatan Gupta nullptr; 23206785244SRatan Gupta }, 23306785244SRatan Gupta ldapDbusService, roleMapObjData[index].first, 23406785244SRatan Gupta "xyz.openbmc_project.Object.Delete", "Delete"); 23506785244SRatan Gupta } 23606785244SRatan Gupta else 23706785244SRatan Gupta { 23806785244SRatan Gupta BMCWEB_LOG_ERROR << "Can't delete the object"; 23906785244SRatan Gupta messages::propertyValueTypeError( 24006785244SRatan Gupta asyncResp->res, thisJson.dump(), 24106785244SRatan Gupta "RemoteRoleMapping/" + std::to_string(index)); 24206785244SRatan Gupta return; 24306785244SRatan Gupta } 24406785244SRatan Gupta } 24506785244SRatan Gupta else if (thisJson.empty()) 24606785244SRatan Gupta { 24706785244SRatan Gupta // Don't do anything for the empty objects,parse next json 24806785244SRatan Gupta // eg {"RemoteRoleMapping",[{}]} 24906785244SRatan Gupta } 25006785244SRatan Gupta else 25106785244SRatan Gupta { 25206785244SRatan Gupta // update/create the object 25306785244SRatan Gupta std::optional<std::string> remoteGroup; 25406785244SRatan Gupta std::optional<std::string> localRole; 25506785244SRatan Gupta 25606785244SRatan Gupta if (!json_util::readJson(thisJson, asyncResp->res, "RemoteGroup", 25706785244SRatan Gupta remoteGroup, "LocalRole", localRole)) 25806785244SRatan Gupta { 25906785244SRatan Gupta continue; 26006785244SRatan Gupta } 26106785244SRatan Gupta 26206785244SRatan Gupta // Update existing RoleMapping Object 26306785244SRatan Gupta if (index < roleMapObjData.size()) 26406785244SRatan Gupta { 26506785244SRatan Gupta BMCWEB_LOG_DEBUG << "Update Role Map Object"; 26606785244SRatan Gupta // If "RemoteGroup" info is provided 26706785244SRatan Gupta if (remoteGroup) 26806785244SRatan Gupta { 26906785244SRatan Gupta crow::connections::systemBus->async_method_call( 27006785244SRatan Gupta [asyncResp, roleMapObjData, serverType, index, 27106785244SRatan Gupta remoteGroup](const boost::system::error_code ec) { 27206785244SRatan Gupta if (ec) 27306785244SRatan Gupta { 27406785244SRatan Gupta BMCWEB_LOG_ERROR << "DBUS response error: " 27506785244SRatan Gupta << ec; 27606785244SRatan Gupta messages::internalError(asyncResp->res); 27706785244SRatan Gupta return; 27806785244SRatan Gupta } 27906785244SRatan Gupta asyncResp->res 28006785244SRatan Gupta .jsonValue[serverType]["RemoteRoleMapping"] 28106785244SRatan Gupta [index]["RemoteGroup"] = *remoteGroup; 28206785244SRatan Gupta }, 28306785244SRatan Gupta ldapDbusService, roleMapObjData[index].first, 28406785244SRatan Gupta propertyInterface, "Set", 28506785244SRatan Gupta "xyz.openbmc_project.User.PrivilegeMapperEntry", 28606785244SRatan Gupta "GroupName", 28706785244SRatan Gupta std::variant<std::string>(std::move(*remoteGroup))); 28806785244SRatan Gupta } 28906785244SRatan Gupta 29006785244SRatan Gupta // If "LocalRole" info is provided 29106785244SRatan Gupta if (localRole) 29206785244SRatan Gupta { 29306785244SRatan Gupta crow::connections::systemBus->async_method_call( 29406785244SRatan Gupta [asyncResp, roleMapObjData, serverType, index, 29506785244SRatan Gupta localRole](const boost::system::error_code ec) { 29606785244SRatan Gupta if (ec) 29706785244SRatan Gupta { 29806785244SRatan Gupta BMCWEB_LOG_ERROR << "DBUS response error: " 29906785244SRatan Gupta << ec; 30006785244SRatan Gupta messages::internalError(asyncResp->res); 30106785244SRatan Gupta return; 30206785244SRatan Gupta } 30306785244SRatan Gupta asyncResp->res 30406785244SRatan Gupta .jsonValue[serverType]["RemoteRoleMapping"] 30506785244SRatan Gupta [index]["LocalRole"] = *localRole; 30606785244SRatan Gupta }, 30706785244SRatan Gupta ldapDbusService, roleMapObjData[index].first, 30806785244SRatan Gupta propertyInterface, "Set", 30906785244SRatan Gupta "xyz.openbmc_project.User.PrivilegeMapperEntry", 31006785244SRatan Gupta "Privilege", 31106785244SRatan Gupta std::variant<std::string>( 31206785244SRatan Gupta getPrivilegeFromRoleId(std::move(*localRole)))); 31306785244SRatan Gupta } 31406785244SRatan Gupta } 31506785244SRatan Gupta // Create a new RoleMapping Object. 31606785244SRatan Gupta else 31706785244SRatan Gupta { 31806785244SRatan Gupta BMCWEB_LOG_DEBUG 31906785244SRatan Gupta << "setRoleMappingProperties: Creating new Object"; 32006785244SRatan Gupta std::string pathString = 32106785244SRatan Gupta "RemoteRoleMapping/" + std::to_string(index); 32206785244SRatan Gupta 32306785244SRatan Gupta if (!localRole) 32406785244SRatan Gupta { 32506785244SRatan Gupta messages::propertyMissing(asyncResp->res, 32606785244SRatan Gupta pathString + "/LocalRole"); 32706785244SRatan Gupta continue; 32806785244SRatan Gupta } 32906785244SRatan Gupta if (!remoteGroup) 33006785244SRatan Gupta { 33106785244SRatan Gupta messages::propertyMissing(asyncResp->res, 33206785244SRatan Gupta pathString + "/RemoteGroup"); 33306785244SRatan Gupta continue; 33406785244SRatan Gupta } 33506785244SRatan Gupta 33606785244SRatan Gupta std::string dbusObjectPath; 33706785244SRatan Gupta if (serverType == "ActiveDirectory") 33806785244SRatan Gupta { 33906785244SRatan Gupta dbusObjectPath = ADConfigObject; 34006785244SRatan Gupta } 34106785244SRatan Gupta else if (serverType == "LDAP") 34206785244SRatan Gupta { 34306785244SRatan Gupta dbusObjectPath = ldapConfigObject; 34406785244SRatan Gupta } 34506785244SRatan Gupta 34606785244SRatan Gupta BMCWEB_LOG_DEBUG << "Remote Group=" << *remoteGroup 34706785244SRatan Gupta << ",LocalRole=" << *localRole; 34806785244SRatan Gupta 34906785244SRatan Gupta crow::connections::systemBus->async_method_call( 350271584abSEd Tanous [asyncResp, serverType, localRole, 35106785244SRatan Gupta remoteGroup](const boost::system::error_code ec) { 35206785244SRatan Gupta if (ec) 35306785244SRatan Gupta { 35406785244SRatan Gupta BMCWEB_LOG_ERROR << "DBUS response error: " << ec; 35506785244SRatan Gupta messages::internalError(asyncResp->res); 35606785244SRatan Gupta return; 35706785244SRatan Gupta } 35806785244SRatan Gupta nlohmann::json& remoteRoleJson = 35906785244SRatan Gupta asyncResp->res 36006785244SRatan Gupta .jsonValue[serverType]["RemoteRoleMapping"]; 36106785244SRatan Gupta remoteRoleJson.push_back( 36206785244SRatan Gupta {{"LocalRole", *localRole}, 36306785244SRatan Gupta {"RemoteGroup", *remoteGroup}}); 36406785244SRatan Gupta }, 36506785244SRatan Gupta ldapDbusService, dbusObjectPath, ldapPrivMapperInterface, 36606785244SRatan Gupta "Create", std::move(*remoteGroup), 36706785244SRatan Gupta getPrivilegeFromRoleId(std::move(*localRole))); 36806785244SRatan Gupta } 36906785244SRatan Gupta } 37006785244SRatan Gupta } 37106785244SRatan Gupta } 37206785244SRatan Gupta 37306785244SRatan Gupta /** 3746973a582SRatan Gupta * Function that retrieves all properties for LDAP config object 3756973a582SRatan Gupta * into JSON 3766973a582SRatan Gupta */ 3776973a582SRatan Gupta template <typename CallbackFunc> 3786973a582SRatan Gupta inline void getLDAPConfigData(const std::string& ldapType, 3796973a582SRatan Gupta CallbackFunc&& callback) 3806973a582SRatan Gupta { 38154fc587aSNagaraju Goruganti 38254fc587aSNagaraju Goruganti const std::array<const char*, 2> interfaces = {ldapEnableInterface, 38354fc587aSNagaraju Goruganti ldapConfigInterface}; 38454fc587aSNagaraju Goruganti 38554fc587aSNagaraju Goruganti crow::connections::systemBus->async_method_call( 38654fc587aSNagaraju Goruganti [callback, ldapType](const boost::system::error_code ec, 38754fc587aSNagaraju Goruganti const GetObjectType& resp) { 38854fc587aSNagaraju Goruganti LDAPConfigData confData{}; 38954fc587aSNagaraju Goruganti if (ec || resp.empty()) 39054fc587aSNagaraju Goruganti { 39154fc587aSNagaraju Goruganti BMCWEB_LOG_ERROR << "DBUS response error during getting of " 39254fc587aSNagaraju Goruganti "service name: " 39354fc587aSNagaraju Goruganti << ec; 39454fc587aSNagaraju Goruganti callback(false, confData, ldapType); 39554fc587aSNagaraju Goruganti return; 39654fc587aSNagaraju Goruganti } 39754fc587aSNagaraju Goruganti std::string service = resp.begin()->first; 39854fc587aSNagaraju Goruganti crow::connections::systemBus->async_method_call( 39954fc587aSNagaraju Goruganti [callback, ldapType](const boost::system::error_code error_code, 4006973a582SRatan Gupta const ManagedObjectType& ldapObjects) { 4016973a582SRatan Gupta LDAPConfigData confData{}; 4026973a582SRatan Gupta if (error_code) 4036973a582SRatan Gupta { 404ab828d7cSRatan Gupta callback(false, confData, ldapType); 40554fc587aSNagaraju Goruganti BMCWEB_LOG_ERROR << "D-Bus responses error: " 40654fc587aSNagaraju Goruganti << error_code; 4076973a582SRatan Gupta return; 4086973a582SRatan Gupta } 409ab828d7cSRatan Gupta 410ab828d7cSRatan Gupta std::string ldapDbusType; 41154fc587aSNagaraju Goruganti std::string searchString; 41254fc587aSNagaraju Goruganti 413ab828d7cSRatan Gupta if (ldapType == "LDAP") 414ab828d7cSRatan Gupta { 41554fc587aSNagaraju Goruganti ldapDbusType = "xyz.openbmc_project.User.Ldap.Config." 41654fc587aSNagaraju Goruganti "Type.OpenLdap"; 41754fc587aSNagaraju Goruganti searchString = "openldap"; 418ab828d7cSRatan Gupta } 419ab828d7cSRatan Gupta else if (ldapType == "ActiveDirectory") 420ab828d7cSRatan Gupta { 42154fc587aSNagaraju Goruganti ldapDbusType = 42254fc587aSNagaraju Goruganti "xyz.openbmc_project.User.Ldap.Config.Type." 423ab828d7cSRatan Gupta "ActiveDirectory"; 42454fc587aSNagaraju Goruganti searchString = "active_directory"; 425ab828d7cSRatan Gupta } 426ab828d7cSRatan Gupta else 427ab828d7cSRatan Gupta { 42854fc587aSNagaraju Goruganti BMCWEB_LOG_ERROR 42954fc587aSNagaraju Goruganti << "Can't get the DbusType for the given type=" 430ab828d7cSRatan Gupta << ldapType; 431ab828d7cSRatan Gupta callback(false, confData, ldapType); 432ab828d7cSRatan Gupta return; 433ab828d7cSRatan Gupta } 434ab828d7cSRatan Gupta 435ab828d7cSRatan Gupta std::string ldapEnableInterfaceStr = ldapEnableInterface; 436ab828d7cSRatan Gupta std::string ldapConfigInterfaceStr = ldapConfigInterface; 437ab828d7cSRatan Gupta 4386973a582SRatan Gupta for (const auto& object : ldapObjects) 4396973a582SRatan Gupta { 44054fc587aSNagaraju Goruganti // let's find the object whose ldap type is equal to the 44154fc587aSNagaraju Goruganti // given type 44254fc587aSNagaraju Goruganti if (object.first.str.find(searchString) == 44354fc587aSNagaraju Goruganti std::string::npos) 4446973a582SRatan Gupta { 445ab828d7cSRatan Gupta continue; 446ab828d7cSRatan Gupta } 447ab828d7cSRatan Gupta 4486973a582SRatan Gupta for (const auto& interface : object.second) 4496973a582SRatan Gupta { 4506973a582SRatan Gupta if (interface.first == ldapEnableInterfaceStr) 4516973a582SRatan Gupta { 4526973a582SRatan Gupta // rest of the properties are string. 4536973a582SRatan Gupta for (const auto& property : interface.second) 4546973a582SRatan Gupta { 4556973a582SRatan Gupta if (property.first == "Enabled") 4566973a582SRatan Gupta { 4576973a582SRatan Gupta const bool* value = 4586973a582SRatan Gupta std::get_if<bool>(&property.second); 4596973a582SRatan Gupta if (value == nullptr) 4606973a582SRatan Gupta { 4616973a582SRatan Gupta continue; 4626973a582SRatan Gupta } 4636973a582SRatan Gupta confData.serviceEnabled = *value; 4646973a582SRatan Gupta break; 4656973a582SRatan Gupta } 4666973a582SRatan Gupta } 4676973a582SRatan Gupta } 4686973a582SRatan Gupta else if (interface.first == ldapConfigInterfaceStr) 4696973a582SRatan Gupta { 4706973a582SRatan Gupta 4716973a582SRatan Gupta for (const auto& property : interface.second) 4726973a582SRatan Gupta { 473271584abSEd Tanous const std::string* strValue = 47454fc587aSNagaraju Goruganti std::get_if<std::string>( 47554fc587aSNagaraju Goruganti &property.second); 476271584abSEd Tanous if (strValue == nullptr) 4776973a582SRatan Gupta { 4786973a582SRatan Gupta continue; 4796973a582SRatan Gupta } 4806973a582SRatan Gupta if (property.first == "LDAPServerURI") 4816973a582SRatan Gupta { 482271584abSEd Tanous confData.uri = *strValue; 4836973a582SRatan Gupta } 4846973a582SRatan Gupta else if (property.first == "LDAPBindDN") 4856973a582SRatan Gupta { 486271584abSEd Tanous confData.bindDN = *strValue; 4876973a582SRatan Gupta } 4886973a582SRatan Gupta else if (property.first == "LDAPBaseDN") 4896973a582SRatan Gupta { 490271584abSEd Tanous confData.baseDN = *strValue; 4916973a582SRatan Gupta } 49254fc587aSNagaraju Goruganti else if (property.first == 49354fc587aSNagaraju Goruganti "LDAPSearchScope") 4946973a582SRatan Gupta { 495271584abSEd Tanous confData.searchScope = *strValue; 4966973a582SRatan Gupta } 49754fc587aSNagaraju Goruganti else if (property.first == 49854fc587aSNagaraju Goruganti "GroupNameAttribute") 4996973a582SRatan Gupta { 500271584abSEd Tanous confData.groupAttribute = *strValue; 5016973a582SRatan Gupta } 50254fc587aSNagaraju Goruganti else if (property.first == 50354fc587aSNagaraju Goruganti "UserNameAttribute") 5046973a582SRatan Gupta { 505271584abSEd Tanous confData.userNameAttribute = *strValue; 5066973a582SRatan Gupta } 50754fc587aSNagaraju Goruganti else if (property.first == "LDAPType") 508ab828d7cSRatan Gupta { 509271584abSEd Tanous confData.serverType = *strValue; 51054fc587aSNagaraju Goruganti } 51154fc587aSNagaraju Goruganti } 51254fc587aSNagaraju Goruganti } 51354fc587aSNagaraju Goruganti else if (interface.first == 51454fc587aSNagaraju Goruganti "xyz.openbmc_project.User." 51554fc587aSNagaraju Goruganti "PrivilegeMapperEntry") 51654fc587aSNagaraju Goruganti { 51754fc587aSNagaraju Goruganti LDAPRoleMapData roleMapData{}; 51854fc587aSNagaraju Goruganti for (const auto& property : interface.second) 51954fc587aSNagaraju Goruganti { 520271584abSEd Tanous const std::string* strValue = 52154fc587aSNagaraju Goruganti std::get_if<std::string>( 52254fc587aSNagaraju Goruganti &property.second); 52354fc587aSNagaraju Goruganti 524271584abSEd Tanous if (strValue == nullptr) 52554fc587aSNagaraju Goruganti { 52654fc587aSNagaraju Goruganti continue; 52754fc587aSNagaraju Goruganti } 52854fc587aSNagaraju Goruganti 52954fc587aSNagaraju Goruganti if (property.first == "GroupName") 53054fc587aSNagaraju Goruganti { 531271584abSEd Tanous roleMapData.groupName = *strValue; 53254fc587aSNagaraju Goruganti } 53354fc587aSNagaraju Goruganti else if (property.first == "Privilege") 53454fc587aSNagaraju Goruganti { 535271584abSEd Tanous roleMapData.privilege = *strValue; 53654fc587aSNagaraju Goruganti } 53754fc587aSNagaraju Goruganti } 53854fc587aSNagaraju Goruganti 5390f0353b6SEd Tanous confData.groupRoleList.emplace_back( 5400f0353b6SEd Tanous object.first.str, roleMapData); 54154fc587aSNagaraju Goruganti } 54254fc587aSNagaraju Goruganti } 54354fc587aSNagaraju Goruganti } 544ab828d7cSRatan Gupta callback(true, confData, ldapType); 54554fc587aSNagaraju Goruganti }, 54654fc587aSNagaraju Goruganti service, ldapRootObject, dbusObjManagerIntf, 5476973a582SRatan Gupta "GetManagedObjects"); 54854fc587aSNagaraju Goruganti }, 54954fc587aSNagaraju Goruganti mapperBusName, mapperObjectPath, mapperIntf, "GetObject", 55054fc587aSNagaraju Goruganti ldapConfigObject, interfaces); 5516973a582SRatan Gupta } 5526973a582SRatan Gupta 5531abe55efSEd Tanous class AccountService : public Node 5541abe55efSEd Tanous { 55588d16c9aSLewanczyk, Dawid public: 556eecd51a4SJames Feist AccountService(CrowApp& app) : Node(app, "/redfish/v1/AccountService/") 5571abe55efSEd Tanous { 5583ebd75f7SEd Tanous entityPrivileges = { 5594b1b8683SBorawski.Lukasz {boost::beast::http::verb::get, 5604b1b8683SBorawski.Lukasz {{"ConfigureUsers"}, {"ConfigureManager"}}}, 561e0d918bcSEd Tanous {boost::beast::http::verb::head, {{"Login"}}}, 562e0d918bcSEd Tanous {boost::beast::http::verb::patch, {{"ConfigureUsers"}}}, 563e0d918bcSEd Tanous {boost::beast::http::verb::put, {{"ConfigureUsers"}}}, 564e0d918bcSEd Tanous {boost::beast::http::verb::delete_, {{"ConfigureUsers"}}}, 565e0d918bcSEd Tanous {boost::beast::http::verb::post, {{"ConfigureUsers"}}}}; 56688d16c9aSLewanczyk, Dawid } 56788d16c9aSLewanczyk, Dawid 56888d16c9aSLewanczyk, Dawid private: 5698a07d286SRatan Gupta /** 5708a07d286SRatan Gupta * @brief parses the authentication section under the LDAP 5718a07d286SRatan Gupta * @param input JSON data 5728a07d286SRatan Gupta * @param asyncResp pointer to the JSON response 5738a07d286SRatan Gupta * @param userName userName to be filled from the given JSON. 5748a07d286SRatan Gupta * @param password password to be filled from the given JSON. 5758a07d286SRatan Gupta */ 5768a07d286SRatan Gupta void 5778a07d286SRatan Gupta parseLDAPAuthenticationJson(nlohmann::json input, 5788a07d286SRatan Gupta const std::shared_ptr<AsyncResp>& asyncResp, 5798a07d286SRatan Gupta std::optional<std::string>& username, 5808a07d286SRatan Gupta std::optional<std::string>& password) 5818a07d286SRatan Gupta { 5828a07d286SRatan Gupta std::optional<std::string> authType; 5838a07d286SRatan Gupta 5848a07d286SRatan Gupta if (!json_util::readJson(input, asyncResp->res, "AuthenticationType", 5858a07d286SRatan Gupta authType, "Username", username, "Password", 5868a07d286SRatan Gupta password)) 5878a07d286SRatan Gupta { 5888a07d286SRatan Gupta return; 5898a07d286SRatan Gupta } 5908a07d286SRatan Gupta if (!authType) 5918a07d286SRatan Gupta { 5928a07d286SRatan Gupta return; 5938a07d286SRatan Gupta } 5948a07d286SRatan Gupta if (*authType != "UsernameAndPassword") 5958a07d286SRatan Gupta { 5968a07d286SRatan Gupta messages::propertyValueNotInList(asyncResp->res, *authType, 5978a07d286SRatan Gupta "AuthenticationType"); 5988a07d286SRatan Gupta return; 5998a07d286SRatan Gupta } 6008a07d286SRatan Gupta } 6018a07d286SRatan Gupta /** 6028a07d286SRatan Gupta * @brief parses the LDAPService section under the LDAP 6038a07d286SRatan Gupta * @param input JSON data 6048a07d286SRatan Gupta * @param asyncResp pointer to the JSON response 6058a07d286SRatan Gupta * @param baseDNList baseDN to be filled from the given JSON. 6068a07d286SRatan Gupta * @param userNameAttribute userName to be filled from the given JSON. 6078a07d286SRatan Gupta * @param groupaAttribute password to be filled from the given JSON. 6088a07d286SRatan Gupta */ 6098a07d286SRatan Gupta 6108a07d286SRatan Gupta void parseLDAPServiceJson( 6118a07d286SRatan Gupta nlohmann::json input, const std::shared_ptr<AsyncResp>& asyncResp, 6128a07d286SRatan Gupta std::optional<std::vector<std::string>>& baseDNList, 6138a07d286SRatan Gupta std::optional<std::string>& userNameAttribute, 6148a07d286SRatan Gupta std::optional<std::string>& groupsAttribute) 6158a07d286SRatan Gupta { 6168a07d286SRatan Gupta std::optional<nlohmann::json> searchSettings; 6178a07d286SRatan Gupta 6188a07d286SRatan Gupta if (!json_util::readJson(input, asyncResp->res, "SearchSettings", 6198a07d286SRatan Gupta searchSettings)) 6208a07d286SRatan Gupta { 6218a07d286SRatan Gupta return; 6228a07d286SRatan Gupta } 6238a07d286SRatan Gupta if (!searchSettings) 6248a07d286SRatan Gupta { 6258a07d286SRatan Gupta return; 6268a07d286SRatan Gupta } 6278a07d286SRatan Gupta if (!json_util::readJson(*searchSettings, asyncResp->res, 6288a07d286SRatan Gupta "BaseDistinguishedNames", baseDNList, 6298a07d286SRatan Gupta "UsernameAttribute", userNameAttribute, 6308a07d286SRatan Gupta "GroupsAttribute", groupsAttribute)) 6318a07d286SRatan Gupta { 6328a07d286SRatan Gupta return; 6338a07d286SRatan Gupta } 6348a07d286SRatan Gupta } 6358a07d286SRatan Gupta /** 6368a07d286SRatan Gupta * @brief updates the LDAP server address and updates the 6378a07d286SRatan Gupta json response with the new value. 6388a07d286SRatan Gupta * @param serviceAddressList address to be updated. 6398a07d286SRatan Gupta * @param asyncResp pointer to the JSON response 6408a07d286SRatan Gupta * @param ldapServerElementName Type of LDAP 6418a07d286SRatan Gupta server(openLDAP/ActiveDirectory) 6428a07d286SRatan Gupta */ 6438a07d286SRatan Gupta 6448a07d286SRatan Gupta void handleServiceAddressPatch( 6458a07d286SRatan Gupta const std::vector<std::string>& serviceAddressList, 6468a07d286SRatan Gupta const std::shared_ptr<AsyncResp>& asyncResp, 6478a07d286SRatan Gupta const std::string& ldapServerElementName, 6488a07d286SRatan Gupta const std::string& ldapConfigObject) 6498a07d286SRatan Gupta { 6508a07d286SRatan Gupta crow::connections::systemBus->async_method_call( 6518a07d286SRatan Gupta [asyncResp, ldapServerElementName, 6528a07d286SRatan Gupta serviceAddressList](const boost::system::error_code ec) { 6538a07d286SRatan Gupta if (ec) 6548a07d286SRatan Gupta { 6558a07d286SRatan Gupta BMCWEB_LOG_DEBUG 6568a07d286SRatan Gupta << "Error Occured in updating the service address"; 6578a07d286SRatan Gupta messages::internalError(asyncResp->res); 6588a07d286SRatan Gupta return; 6598a07d286SRatan Gupta } 6608a07d286SRatan Gupta std::vector<std::string> modifiedserviceAddressList = { 6618a07d286SRatan Gupta serviceAddressList.front()}; 6628a07d286SRatan Gupta asyncResp->res 6638a07d286SRatan Gupta .jsonValue[ldapServerElementName]["ServiceAddresses"] = 6648a07d286SRatan Gupta modifiedserviceAddressList; 6658a07d286SRatan Gupta if ((serviceAddressList).size() > 1) 6668a07d286SRatan Gupta { 6678a07d286SRatan Gupta messages::propertyValueModified(asyncResp->res, 6688a07d286SRatan Gupta "ServiceAddresses", 6698a07d286SRatan Gupta serviceAddressList.front()); 6708a07d286SRatan Gupta } 6718a07d286SRatan Gupta BMCWEB_LOG_DEBUG << "Updated the service address"; 6728a07d286SRatan Gupta }, 6738a07d286SRatan Gupta ldapDbusService, ldapConfigObject, propertyInterface, "Set", 6748a07d286SRatan Gupta ldapConfigInterface, "LDAPServerURI", 6758a07d286SRatan Gupta std::variant<std::string>(serviceAddressList.front())); 6768a07d286SRatan Gupta } 6778a07d286SRatan Gupta /** 6788a07d286SRatan Gupta * @brief updates the LDAP Bind DN and updates the 6798a07d286SRatan Gupta json response with the new value. 6808a07d286SRatan Gupta * @param username name of the user which needs to be updated. 6818a07d286SRatan Gupta * @param asyncResp pointer to the JSON response 6828a07d286SRatan Gupta * @param ldapServerElementName Type of LDAP 6838a07d286SRatan Gupta server(openLDAP/ActiveDirectory) 6848a07d286SRatan Gupta */ 6858a07d286SRatan Gupta 6868a07d286SRatan Gupta void handleUserNamePatch(const std::string& username, 6878a07d286SRatan Gupta const std::shared_ptr<AsyncResp>& asyncResp, 6888a07d286SRatan Gupta const std::string& ldapServerElementName, 6898a07d286SRatan Gupta const std::string& ldapConfigObject) 6908a07d286SRatan Gupta { 6918a07d286SRatan Gupta crow::connections::systemBus->async_method_call( 6928a07d286SRatan Gupta [asyncResp, username, 6938a07d286SRatan Gupta ldapServerElementName](const boost::system::error_code ec) { 6948a07d286SRatan Gupta if (ec) 6958a07d286SRatan Gupta { 6968a07d286SRatan Gupta BMCWEB_LOG_DEBUG 6978a07d286SRatan Gupta << "Error occured in updating the username"; 6988a07d286SRatan Gupta messages::internalError(asyncResp->res); 6998a07d286SRatan Gupta return; 7008a07d286SRatan Gupta } 7018a07d286SRatan Gupta asyncResp->res.jsonValue[ldapServerElementName] 7028a07d286SRatan Gupta ["Authentication"]["Username"] = 7038a07d286SRatan Gupta username; 7048a07d286SRatan Gupta BMCWEB_LOG_DEBUG << "Updated the username"; 7058a07d286SRatan Gupta }, 7068a07d286SRatan Gupta ldapDbusService, ldapConfigObject, propertyInterface, "Set", 7078a07d286SRatan Gupta ldapConfigInterface, "LDAPBindDN", 7088a07d286SRatan Gupta std::variant<std::string>(username)); 7098a07d286SRatan Gupta } 7108a07d286SRatan Gupta 7118a07d286SRatan Gupta /** 7128a07d286SRatan Gupta * @brief updates the LDAP password 7138a07d286SRatan Gupta * @param password : ldap password which needs to be updated. 7148a07d286SRatan Gupta * @param asyncResp pointer to the JSON response 7158a07d286SRatan Gupta * @param ldapServerElementName Type of LDAP 7168a07d286SRatan Gupta * server(openLDAP/ActiveDirectory) 7178a07d286SRatan Gupta */ 7188a07d286SRatan Gupta 7198a07d286SRatan Gupta void handlePasswordPatch(const std::string& password, 7208a07d286SRatan Gupta const std::shared_ptr<AsyncResp>& asyncResp, 7218a07d286SRatan Gupta const std::string& ldapServerElementName, 7228a07d286SRatan Gupta const std::string& ldapConfigObject) 7238a07d286SRatan Gupta { 7248a07d286SRatan Gupta crow::connections::systemBus->async_method_call( 7258a07d286SRatan Gupta [asyncResp, password, 7268a07d286SRatan Gupta ldapServerElementName](const boost::system::error_code ec) { 7278a07d286SRatan Gupta if (ec) 7288a07d286SRatan Gupta { 7298a07d286SRatan Gupta BMCWEB_LOG_DEBUG 7308a07d286SRatan Gupta << "Error occured in updating the password"; 7318a07d286SRatan Gupta messages::internalError(asyncResp->res); 7328a07d286SRatan Gupta return; 7338a07d286SRatan Gupta } 7348a07d286SRatan Gupta asyncResp->res.jsonValue[ldapServerElementName] 7358a07d286SRatan Gupta ["Authentication"]["Password"] = ""; 7368a07d286SRatan Gupta BMCWEB_LOG_DEBUG << "Updated the password"; 7378a07d286SRatan Gupta }, 7388a07d286SRatan Gupta ldapDbusService, ldapConfigObject, propertyInterface, "Set", 7398a07d286SRatan Gupta ldapConfigInterface, "LDAPBindDNPassword", 7408a07d286SRatan Gupta std::variant<std::string>(password)); 7418a07d286SRatan Gupta } 7428a07d286SRatan Gupta 7438a07d286SRatan Gupta /** 7448a07d286SRatan Gupta * @brief updates the LDAP BaseDN and updates the 7458a07d286SRatan Gupta json response with the new value. 7468a07d286SRatan Gupta * @param baseDNList baseDN list which needs to be updated. 7478a07d286SRatan Gupta * @param asyncResp pointer to the JSON response 7488a07d286SRatan Gupta * @param ldapServerElementName Type of LDAP 7498a07d286SRatan Gupta server(openLDAP/ActiveDirectory) 7508a07d286SRatan Gupta */ 7518a07d286SRatan Gupta 7528a07d286SRatan Gupta void handleBaseDNPatch(const std::vector<std::string>& baseDNList, 7538a07d286SRatan Gupta const std::shared_ptr<AsyncResp>& asyncResp, 7548a07d286SRatan Gupta const std::string& ldapServerElementName, 7558a07d286SRatan Gupta const std::string& ldapConfigObject) 7568a07d286SRatan Gupta { 7578a07d286SRatan Gupta crow::connections::systemBus->async_method_call( 7588a07d286SRatan Gupta [asyncResp, baseDNList, 7598a07d286SRatan Gupta ldapServerElementName](const boost::system::error_code ec) { 7608a07d286SRatan Gupta if (ec) 7618a07d286SRatan Gupta { 7628a07d286SRatan Gupta BMCWEB_LOG_DEBUG << "Error Occured in Updating the base DN"; 7638a07d286SRatan Gupta messages::internalError(asyncResp->res); 7648a07d286SRatan Gupta return; 7658a07d286SRatan Gupta } 7668a07d286SRatan Gupta auto& serverTypeJson = 7678a07d286SRatan Gupta asyncResp->res.jsonValue[ldapServerElementName]; 7688a07d286SRatan Gupta auto& searchSettingsJson = 7698a07d286SRatan Gupta serverTypeJson["LDAPService"]["SearchSettings"]; 7708a07d286SRatan Gupta std::vector<std::string> modifiedBaseDNList = { 7718a07d286SRatan Gupta baseDNList.front()}; 7728a07d286SRatan Gupta searchSettingsJson["BaseDistinguishedNames"] = 7738a07d286SRatan Gupta modifiedBaseDNList; 7748a07d286SRatan Gupta if (baseDNList.size() > 1) 7758a07d286SRatan Gupta { 7768a07d286SRatan Gupta messages::propertyValueModified(asyncResp->res, 7778a07d286SRatan Gupta "BaseDistinguishedNames", 7788a07d286SRatan Gupta baseDNList.front()); 7798a07d286SRatan Gupta } 7808a07d286SRatan Gupta BMCWEB_LOG_DEBUG << "Updated the base DN"; 7818a07d286SRatan Gupta }, 7828a07d286SRatan Gupta ldapDbusService, ldapConfigObject, propertyInterface, "Set", 7838a07d286SRatan Gupta ldapConfigInterface, "LDAPBaseDN", 7848a07d286SRatan Gupta std::variant<std::string>(baseDNList.front())); 7858a07d286SRatan Gupta } 7868a07d286SRatan Gupta /** 7878a07d286SRatan Gupta * @brief updates the LDAP user name attribute and updates the 7888a07d286SRatan Gupta json response with the new value. 7898a07d286SRatan Gupta * @param userNameAttribute attribute to be updated. 7908a07d286SRatan Gupta * @param asyncResp pointer to the JSON response 7918a07d286SRatan Gupta * @param ldapServerElementName Type of LDAP 7928a07d286SRatan Gupta server(openLDAP/ActiveDirectory) 7938a07d286SRatan Gupta */ 7948a07d286SRatan Gupta 7958a07d286SRatan Gupta void handleUserNameAttrPatch(const std::string& userNameAttribute, 7968a07d286SRatan Gupta const std::shared_ptr<AsyncResp>& asyncResp, 7978a07d286SRatan Gupta const std::string& ldapServerElementName, 7988a07d286SRatan Gupta const std::string& ldapConfigObject) 7998a07d286SRatan Gupta { 8008a07d286SRatan Gupta crow::connections::systemBus->async_method_call( 8018a07d286SRatan Gupta [asyncResp, userNameAttribute, 8028a07d286SRatan Gupta ldapServerElementName](const boost::system::error_code ec) { 8038a07d286SRatan Gupta if (ec) 8048a07d286SRatan Gupta { 8058a07d286SRatan Gupta BMCWEB_LOG_DEBUG << "Error Occured in Updating the " 8068a07d286SRatan Gupta "username attribute"; 8078a07d286SRatan Gupta messages::internalError(asyncResp->res); 8088a07d286SRatan Gupta return; 8098a07d286SRatan Gupta } 8108a07d286SRatan Gupta auto& serverTypeJson = 8118a07d286SRatan Gupta asyncResp->res.jsonValue[ldapServerElementName]; 8128a07d286SRatan Gupta auto& searchSettingsJson = 8138a07d286SRatan Gupta serverTypeJson["LDAPService"]["SearchSettings"]; 8148a07d286SRatan Gupta searchSettingsJson["UsernameAttribute"] = userNameAttribute; 8158a07d286SRatan Gupta BMCWEB_LOG_DEBUG << "Updated the user name attr."; 8168a07d286SRatan Gupta }, 8178a07d286SRatan Gupta ldapDbusService, ldapConfigObject, propertyInterface, "Set", 8188a07d286SRatan Gupta ldapConfigInterface, "UserNameAttribute", 8198a07d286SRatan Gupta std::variant<std::string>(userNameAttribute)); 8208a07d286SRatan Gupta } 8218a07d286SRatan Gupta /** 8228a07d286SRatan Gupta * @brief updates the LDAP group attribute and updates the 8238a07d286SRatan Gupta json response with the new value. 8248a07d286SRatan Gupta * @param groupsAttribute attribute to be updated. 8258a07d286SRatan Gupta * @param asyncResp pointer to the JSON response 8268a07d286SRatan Gupta * @param ldapServerElementName Type of LDAP 8278a07d286SRatan Gupta server(openLDAP/ActiveDirectory) 8288a07d286SRatan Gupta */ 8298a07d286SRatan Gupta 8308a07d286SRatan Gupta void handleGroupNameAttrPatch(const std::string& groupsAttribute, 8318a07d286SRatan Gupta const std::shared_ptr<AsyncResp>& asyncResp, 8328a07d286SRatan Gupta const std::string& ldapServerElementName, 8338a07d286SRatan Gupta const std::string& ldapConfigObject) 8348a07d286SRatan Gupta { 8358a07d286SRatan Gupta crow::connections::systemBus->async_method_call( 8368a07d286SRatan Gupta [asyncResp, groupsAttribute, 8378a07d286SRatan Gupta ldapServerElementName](const boost::system::error_code ec) { 8388a07d286SRatan Gupta if (ec) 8398a07d286SRatan Gupta { 8408a07d286SRatan Gupta BMCWEB_LOG_DEBUG << "Error Occured in Updating the " 8418a07d286SRatan Gupta "groupname attribute"; 8428a07d286SRatan Gupta messages::internalError(asyncResp->res); 8438a07d286SRatan Gupta return; 8448a07d286SRatan Gupta } 8458a07d286SRatan Gupta auto& serverTypeJson = 8468a07d286SRatan Gupta asyncResp->res.jsonValue[ldapServerElementName]; 8478a07d286SRatan Gupta auto& searchSettingsJson = 8488a07d286SRatan Gupta serverTypeJson["LDAPService"]["SearchSettings"]; 8498a07d286SRatan Gupta searchSettingsJson["GroupsAttribute"] = groupsAttribute; 8508a07d286SRatan Gupta BMCWEB_LOG_DEBUG << "Updated the groupname attr"; 8518a07d286SRatan Gupta }, 8528a07d286SRatan Gupta ldapDbusService, ldapConfigObject, propertyInterface, "Set", 8538a07d286SRatan Gupta ldapConfigInterface, "GroupNameAttribute", 8548a07d286SRatan Gupta std::variant<std::string>(groupsAttribute)); 8558a07d286SRatan Gupta } 8568a07d286SRatan Gupta /** 8578a07d286SRatan Gupta * @brief updates the LDAP service enable and updates the 8588a07d286SRatan Gupta json response with the new value. 8598a07d286SRatan Gupta * @param input JSON data. 8608a07d286SRatan Gupta * @param asyncResp pointer to the JSON response 8618a07d286SRatan Gupta * @param ldapServerElementName Type of LDAP 8628a07d286SRatan Gupta server(openLDAP/ActiveDirectory) 8638a07d286SRatan Gupta */ 8648a07d286SRatan Gupta 8658a07d286SRatan Gupta void handleServiceEnablePatch(bool serviceEnabled, 8668a07d286SRatan Gupta const std::shared_ptr<AsyncResp>& asyncResp, 8678a07d286SRatan Gupta const std::string& ldapServerElementName, 8688a07d286SRatan Gupta const std::string& ldapConfigObject) 8698a07d286SRatan Gupta { 8708a07d286SRatan Gupta crow::connections::systemBus->async_method_call( 8718a07d286SRatan Gupta [asyncResp, serviceEnabled, 8728a07d286SRatan Gupta ldapServerElementName](const boost::system::error_code ec) { 8738a07d286SRatan Gupta if (ec) 8748a07d286SRatan Gupta { 8758a07d286SRatan Gupta BMCWEB_LOG_DEBUG 8768a07d286SRatan Gupta << "Error Occured in Updating the service enable"; 8778a07d286SRatan Gupta messages::internalError(asyncResp->res); 8788a07d286SRatan Gupta return; 8798a07d286SRatan Gupta } 8808a07d286SRatan Gupta asyncResp->res 8818a07d286SRatan Gupta .jsonValue[ldapServerElementName]["ServiceEnabled"] = 8828a07d286SRatan Gupta serviceEnabled; 8838a07d286SRatan Gupta BMCWEB_LOG_DEBUG << "Updated Service enable = " 8848a07d286SRatan Gupta << serviceEnabled; 8858a07d286SRatan Gupta }, 8868a07d286SRatan Gupta ldapDbusService, ldapConfigObject, propertyInterface, "Set", 8878a07d286SRatan Gupta ldapEnableInterface, "Enabled", std::variant<bool>(serviceEnabled)); 8888a07d286SRatan Gupta } 8898a07d286SRatan Gupta 8908a07d286SRatan Gupta /** 8918a07d286SRatan Gupta * @brief Get the required values from the given JSON, validates the 8928a07d286SRatan Gupta * value and create the LDAP config object. 8938a07d286SRatan Gupta * @param input JSON data 8948a07d286SRatan Gupta * @param asyncResp pointer to the JSON response 8958a07d286SRatan Gupta * @param serverType Type of LDAP server(openLDAP/ActiveDirectory) 8968a07d286SRatan Gupta */ 8978a07d286SRatan Gupta 8988a07d286SRatan Gupta void handleLDAPPatch(nlohmann::json& input, 8998a07d286SRatan Gupta const std::shared_ptr<AsyncResp>& asyncResp, 9008a07d286SRatan Gupta const crow::Request& req, 9018a07d286SRatan Gupta const std::vector<std::string>& params, 9028a07d286SRatan Gupta const std::string& serverType) 9038a07d286SRatan Gupta { 904eb2bbe56SRatan Gupta std::string dbusObjectPath; 905eb2bbe56SRatan Gupta if (serverType == "ActiveDirectory") 906eb2bbe56SRatan Gupta { 907eb2bbe56SRatan Gupta dbusObjectPath = ADConfigObject; 908eb2bbe56SRatan Gupta } 909eb2bbe56SRatan Gupta else if (serverType == "LDAP") 910eb2bbe56SRatan Gupta { 911eb2bbe56SRatan Gupta dbusObjectPath = ldapConfigObject; 912eb2bbe56SRatan Gupta } 913eb2bbe56SRatan Gupta 9148a07d286SRatan Gupta std::optional<nlohmann::json> authentication; 9158a07d286SRatan Gupta std::optional<nlohmann::json> ldapService; 9168a07d286SRatan Gupta std::optional<std::string> accountProviderType; 9178a07d286SRatan Gupta std::optional<std::vector<std::string>> serviceAddressList; 9188a07d286SRatan Gupta std::optional<bool> serviceEnabled; 9198a07d286SRatan Gupta std::optional<std::vector<std::string>> baseDNList; 9208a07d286SRatan Gupta std::optional<std::string> userNameAttribute; 9218a07d286SRatan Gupta std::optional<std::string> groupsAttribute; 9228a07d286SRatan Gupta std::optional<std::string> userName; 9238a07d286SRatan Gupta std::optional<std::string> password; 92406785244SRatan Gupta std::optional<std::vector<nlohmann::json>> remoteRoleMapData; 9258a07d286SRatan Gupta 9268a07d286SRatan Gupta if (!json_util::readJson(input, asyncResp->res, "Authentication", 9278a07d286SRatan Gupta authentication, "LDAPService", ldapService, 9288a07d286SRatan Gupta "ServiceAddresses", serviceAddressList, 9298a07d286SRatan Gupta "AccountProviderType", accountProviderType, 93006785244SRatan Gupta "ServiceEnabled", serviceEnabled, 93106785244SRatan Gupta "RemoteRoleMapping", remoteRoleMapData)) 9328a07d286SRatan Gupta { 9338a07d286SRatan Gupta return; 9348a07d286SRatan Gupta } 9358a07d286SRatan Gupta 9368a07d286SRatan Gupta if (authentication) 9378a07d286SRatan Gupta { 9388a07d286SRatan Gupta parseLDAPAuthenticationJson(*authentication, asyncResp, userName, 9398a07d286SRatan Gupta password); 9408a07d286SRatan Gupta } 9418a07d286SRatan Gupta if (ldapService) 9428a07d286SRatan Gupta { 9438a07d286SRatan Gupta parseLDAPServiceJson(*ldapService, asyncResp, baseDNList, 9448a07d286SRatan Gupta userNameAttribute, groupsAttribute); 9458a07d286SRatan Gupta } 9468a07d286SRatan Gupta if (accountProviderType) 9478a07d286SRatan Gupta { 9488a07d286SRatan Gupta messages::propertyNotWritable(asyncResp->res, 9498a07d286SRatan Gupta "AccountProviderType"); 9508a07d286SRatan Gupta } 9518a07d286SRatan Gupta if (serviceAddressList) 9528a07d286SRatan Gupta { 9538a07d286SRatan Gupta if ((*serviceAddressList).size() == 0) 9548a07d286SRatan Gupta { 9558a07d286SRatan Gupta messages::propertyValueNotInList(asyncResp->res, "[]", 9568a07d286SRatan Gupta "ServiceAddress"); 9578a07d286SRatan Gupta return; 9588a07d286SRatan Gupta } 9598a07d286SRatan Gupta } 9608a07d286SRatan Gupta if (baseDNList) 9618a07d286SRatan Gupta { 9628a07d286SRatan Gupta if ((*baseDNList).size() == 0) 9638a07d286SRatan Gupta { 9648a07d286SRatan Gupta messages::propertyValueNotInList(asyncResp->res, "[]", 9658a07d286SRatan Gupta "BaseDistinguishedNames"); 9668a07d286SRatan Gupta return; 9678a07d286SRatan Gupta } 9688a07d286SRatan Gupta } 9698a07d286SRatan Gupta 9708a07d286SRatan Gupta // nothing to update, then return 9718a07d286SRatan Gupta if (!userName && !password && !serviceAddressList && !baseDNList && 97206785244SRatan Gupta !userNameAttribute && !groupsAttribute && !serviceEnabled && 97306785244SRatan Gupta !remoteRoleMapData) 9748a07d286SRatan Gupta { 9758a07d286SRatan Gupta return; 9768a07d286SRatan Gupta } 9778a07d286SRatan Gupta 9788a07d286SRatan Gupta // Get the existing resource first then keep modifying 9798a07d286SRatan Gupta // whenever any property gets updated. 980ab828d7cSRatan Gupta getLDAPConfigData(serverType, [this, asyncResp, userName, password, 981ab828d7cSRatan Gupta baseDNList, userNameAttribute, 982ab828d7cSRatan Gupta groupsAttribute, accountProviderType, 983eb2bbe56SRatan Gupta serviceAddressList, serviceEnabled, 98406785244SRatan Gupta dbusObjectPath, remoteRoleMapData]( 985ab828d7cSRatan Gupta bool success, LDAPConfigData confData, 986ab828d7cSRatan Gupta const std::string& serverType) { 9878a07d286SRatan Gupta if (!success) 9888a07d286SRatan Gupta { 9898a07d286SRatan Gupta messages::internalError(asyncResp->res); 9908a07d286SRatan Gupta return; 9918a07d286SRatan Gupta } 992ab828d7cSRatan Gupta parseLDAPConfigData(asyncResp->res.jsonValue, confData, serverType); 9938a07d286SRatan Gupta if (confData.serviceEnabled) 9948a07d286SRatan Gupta { 9958a07d286SRatan Gupta // Disable the service first and update the rest of 9968a07d286SRatan Gupta // the properties. 9978a07d286SRatan Gupta handleServiceEnablePatch(false, asyncResp, serverType, 998eb2bbe56SRatan Gupta dbusObjectPath); 9998a07d286SRatan Gupta } 10008a07d286SRatan Gupta 10018a07d286SRatan Gupta if (serviceAddressList) 10028a07d286SRatan Gupta { 10038a07d286SRatan Gupta handleServiceAddressPatch(*serviceAddressList, asyncResp, 1004eb2bbe56SRatan Gupta serverType, dbusObjectPath); 10058a07d286SRatan Gupta } 10068a07d286SRatan Gupta if (userName) 10078a07d286SRatan Gupta { 10088a07d286SRatan Gupta handleUserNamePatch(*userName, asyncResp, serverType, 1009eb2bbe56SRatan Gupta dbusObjectPath); 10108a07d286SRatan Gupta } 10118a07d286SRatan Gupta if (password) 10128a07d286SRatan Gupta { 10138a07d286SRatan Gupta handlePasswordPatch(*password, asyncResp, serverType, 1014eb2bbe56SRatan Gupta dbusObjectPath); 10158a07d286SRatan Gupta } 10168a07d286SRatan Gupta 10178a07d286SRatan Gupta if (baseDNList) 10188a07d286SRatan Gupta { 10198a07d286SRatan Gupta handleBaseDNPatch(*baseDNList, asyncResp, serverType, 1020eb2bbe56SRatan Gupta dbusObjectPath); 10218a07d286SRatan Gupta } 10228a07d286SRatan Gupta if (userNameAttribute) 10238a07d286SRatan Gupta { 10248a07d286SRatan Gupta handleUserNameAttrPatch(*userNameAttribute, asyncResp, 1025eb2bbe56SRatan Gupta serverType, dbusObjectPath); 10268a07d286SRatan Gupta } 10278a07d286SRatan Gupta if (groupsAttribute) 10288a07d286SRatan Gupta { 10298a07d286SRatan Gupta handleGroupNameAttrPatch(*groupsAttribute, asyncResp, 1030eb2bbe56SRatan Gupta serverType, dbusObjectPath); 10318a07d286SRatan Gupta } 10328a07d286SRatan Gupta if (serviceEnabled) 10338a07d286SRatan Gupta { 10348a07d286SRatan Gupta // if user has given the value as true then enable 10358a07d286SRatan Gupta // the service. if user has given false then no-op 10368a07d286SRatan Gupta // as service is already stopped. 10378a07d286SRatan Gupta if (*serviceEnabled) 10388a07d286SRatan Gupta { 10398a07d286SRatan Gupta handleServiceEnablePatch(*serviceEnabled, asyncResp, 1040eb2bbe56SRatan Gupta serverType, dbusObjectPath); 10418a07d286SRatan Gupta } 10428a07d286SRatan Gupta } 10438a07d286SRatan Gupta else 10448a07d286SRatan Gupta { 10458a07d286SRatan Gupta // if user has not given the service enabled value 10468a07d286SRatan Gupta // then revert it to the same state as it was 10478a07d286SRatan Gupta // before. 10488a07d286SRatan Gupta handleServiceEnablePatch(confData.serviceEnabled, asyncResp, 1049eb2bbe56SRatan Gupta serverType, dbusObjectPath); 10508a07d286SRatan Gupta } 105106785244SRatan Gupta 105206785244SRatan Gupta if (remoteRoleMapData) 105306785244SRatan Gupta { 105406785244SRatan Gupta std::vector<nlohmann::json> remoteRoleMap = 105506785244SRatan Gupta std::move(*remoteRoleMapData); 105606785244SRatan Gupta 105706785244SRatan Gupta handleRoleMapPatch(asyncResp, confData.groupRoleList, 105806785244SRatan Gupta serverType, remoteRoleMap); 105906785244SRatan Gupta } 10608a07d286SRatan Gupta }); 10618a07d286SRatan Gupta } 1062d4b5443fSEd Tanous 106355c7b7a2SEd Tanous void doGet(crow::Response& res, const crow::Request& req, 10641abe55efSEd Tanous const std::vector<std::string>& params) override 10651abe55efSEd Tanous { 10663d958bbcSAppaRao Puli auto asyncResp = std::make_shared<AsyncResp>(res); 10673d958bbcSAppaRao Puli res.jsonValue = { 10683d958bbcSAppaRao Puli {"@odata.context", "/redfish/v1/" 10693d958bbcSAppaRao Puli "$metadata#AccountService.AccountService"}, 10703d958bbcSAppaRao Puli {"@odata.id", "/redfish/v1/AccountService"}, 10713d958bbcSAppaRao Puli {"@odata.type", "#AccountService." 107237cce918SMarri Devender Rao "v1_4_0.AccountService"}, 10733d958bbcSAppaRao Puli {"Id", "AccountService"}, 10743d958bbcSAppaRao Puli {"Name", "Account Service"}, 10753d958bbcSAppaRao Puli {"Description", "Account Service"}, 10763d958bbcSAppaRao Puli {"ServiceEnabled", true}, 1077343ff2e1SAppaRao Puli {"MaxPasswordLength", 20}, 10783d958bbcSAppaRao Puli {"Accounts", 10793d958bbcSAppaRao Puli {{"@odata.id", "/redfish/v1/AccountService/Accounts"}}}, 108037cce918SMarri Devender Rao {"Roles", {{"@odata.id", "/redfish/v1/AccountService/Roles"}}}, 108137cce918SMarri Devender Rao {"LDAP", 108237cce918SMarri Devender Rao {{"Certificates", 108337cce918SMarri Devender Rao {{"@odata.id", 108437cce918SMarri Devender Rao "/redfish/v1/AccountService/LDAP/Certificates"}}}}}}; 10853d958bbcSAppaRao Puli crow::connections::systemBus->async_method_call( 10863d958bbcSAppaRao Puli [asyncResp]( 10873d958bbcSAppaRao Puli const boost::system::error_code ec, 10883d958bbcSAppaRao Puli const std::vector<std::pair< 1089abf2add6SEd Tanous std::string, std::variant<uint32_t, uint16_t, uint8_t>>>& 10903d958bbcSAppaRao Puli propertiesList) { 10913d958bbcSAppaRao Puli if (ec) 10923d958bbcSAppaRao Puli { 10933d958bbcSAppaRao Puli messages::internalError(asyncResp->res); 10943d958bbcSAppaRao Puli return; 10953d958bbcSAppaRao Puli } 10963d958bbcSAppaRao Puli BMCWEB_LOG_DEBUG << "Got " << propertiesList.size() 10973d958bbcSAppaRao Puli << "properties for AccountService"; 10983d958bbcSAppaRao Puli for (const std::pair<std::string, 1099abf2add6SEd Tanous std::variant<uint32_t, uint16_t, uint8_t>>& 11003d958bbcSAppaRao Puli property : propertiesList) 11013d958bbcSAppaRao Puli { 11023d958bbcSAppaRao Puli if (property.first == "MinPasswordLength") 11033d958bbcSAppaRao Puli { 11043d958bbcSAppaRao Puli const uint8_t* value = 1105abf2add6SEd Tanous std::get_if<uint8_t>(&property.second); 11063d958bbcSAppaRao Puli if (value != nullptr) 11073d958bbcSAppaRao Puli { 11083d958bbcSAppaRao Puli asyncResp->res.jsonValue["MinPasswordLength"] = 11093d958bbcSAppaRao Puli *value; 11103d958bbcSAppaRao Puli } 11113d958bbcSAppaRao Puli } 11123d958bbcSAppaRao Puli if (property.first == "AccountUnlockTimeout") 11133d958bbcSAppaRao Puli { 11143d958bbcSAppaRao Puli const uint32_t* value = 1115abf2add6SEd Tanous std::get_if<uint32_t>(&property.second); 11163d958bbcSAppaRao Puli if (value != nullptr) 11173d958bbcSAppaRao Puli { 11183d958bbcSAppaRao Puli asyncResp->res.jsonValue["AccountLockoutDuration"] = 11193d958bbcSAppaRao Puli *value; 11203d958bbcSAppaRao Puli } 11213d958bbcSAppaRao Puli } 11223d958bbcSAppaRao Puli if (property.first == "MaxLoginAttemptBeforeLockout") 11233d958bbcSAppaRao Puli { 11243d958bbcSAppaRao Puli const uint16_t* value = 1125abf2add6SEd Tanous std::get_if<uint16_t>(&property.second); 11263d958bbcSAppaRao Puli if (value != nullptr) 11273d958bbcSAppaRao Puli { 11283d958bbcSAppaRao Puli asyncResp->res 11293d958bbcSAppaRao Puli .jsonValue["AccountLockoutThreshold"] = *value; 11303d958bbcSAppaRao Puli } 11313d958bbcSAppaRao Puli } 11323d958bbcSAppaRao Puli } 11333d958bbcSAppaRao Puli }, 11343d958bbcSAppaRao Puli "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user", 11353d958bbcSAppaRao Puli "org.freedesktop.DBus.Properties", "GetAll", 11363d958bbcSAppaRao Puli "xyz.openbmc_project.User.AccountPolicy"); 11376973a582SRatan Gupta 1138ab828d7cSRatan Gupta auto callback = [asyncResp](bool success, LDAPConfigData& confData, 1139ab828d7cSRatan Gupta const std::string& ldapType) { 1140ab828d7cSRatan Gupta parseLDAPConfigData(asyncResp->res.jsonValue, confData, ldapType); 1141ab828d7cSRatan Gupta }; 1142ab828d7cSRatan Gupta 1143ab828d7cSRatan Gupta getLDAPConfigData("LDAP", callback); 1144ab828d7cSRatan Gupta getLDAPConfigData("ActiveDirectory", callback); 11453d958bbcSAppaRao Puli } 11466973a582SRatan Gupta 11473d958bbcSAppaRao Puli void doPatch(crow::Response& res, const crow::Request& req, 11483d958bbcSAppaRao Puli const std::vector<std::string>& params) override 11493d958bbcSAppaRao Puli { 11503d958bbcSAppaRao Puli auto asyncResp = std::make_shared<AsyncResp>(res); 11513d958bbcSAppaRao Puli 11523d958bbcSAppaRao Puli std::optional<uint32_t> unlockTimeout; 11533d958bbcSAppaRao Puli std::optional<uint16_t> lockoutThreshold; 115419fb6e71SRatan Gupta std::optional<uint16_t> minPasswordLength; 115519fb6e71SRatan Gupta std::optional<uint16_t> maxPasswordLength; 11568a07d286SRatan Gupta std::optional<nlohmann::json> ldapObject; 1157eb2bbe56SRatan Gupta std::optional<nlohmann::json> activeDirectoryObject; 115819fb6e71SRatan Gupta 1159eecd51a4SJames Feist if (!json_util::readJson(req, res, "AccountLockoutDuration", 1160eecd51a4SJames Feist unlockTimeout, "AccountLockoutThreshold", 1161eecd51a4SJames Feist lockoutThreshold, "MaxPasswordLength", 1162eecd51a4SJames Feist maxPasswordLength, "MinPasswordLength", 1163eecd51a4SJames Feist minPasswordLength, "LDAP", ldapObject, 1164eecd51a4SJames Feist "ActiveDirectory", activeDirectoryObject)) 11653d958bbcSAppaRao Puli { 11663d958bbcSAppaRao Puli return; 11673d958bbcSAppaRao Puli } 116819fb6e71SRatan Gupta 116919fb6e71SRatan Gupta if (minPasswordLength) 117019fb6e71SRatan Gupta { 117119fb6e71SRatan Gupta messages::propertyNotWritable(asyncResp->res, "MinPasswordLength"); 117219fb6e71SRatan Gupta } 117319fb6e71SRatan Gupta 117419fb6e71SRatan Gupta if (maxPasswordLength) 117519fb6e71SRatan Gupta { 117619fb6e71SRatan Gupta messages::propertyNotWritable(asyncResp->res, "MaxPasswordLength"); 117719fb6e71SRatan Gupta } 117819fb6e71SRatan Gupta 11798a07d286SRatan Gupta if (ldapObject) 11808a07d286SRatan Gupta { 11818a07d286SRatan Gupta handleLDAPPatch(*ldapObject, asyncResp, req, params, "LDAP"); 11828a07d286SRatan Gupta } 11838a07d286SRatan Gupta 1184eb2bbe56SRatan Gupta if (activeDirectoryObject) 1185eb2bbe56SRatan Gupta { 1186eb2bbe56SRatan Gupta handleLDAPPatch(*activeDirectoryObject, asyncResp, req, params, 1187eb2bbe56SRatan Gupta "ActiveDirectory"); 1188eb2bbe56SRatan Gupta } 1189eb2bbe56SRatan Gupta 11903d958bbcSAppaRao Puli if (unlockTimeout) 11913d958bbcSAppaRao Puli { 11923d958bbcSAppaRao Puli crow::connections::systemBus->async_method_call( 11933d958bbcSAppaRao Puli [asyncResp](const boost::system::error_code ec) { 11943d958bbcSAppaRao Puli if (ec) 11953d958bbcSAppaRao Puli { 11963d958bbcSAppaRao Puli messages::internalError(asyncResp->res); 11973d958bbcSAppaRao Puli return; 11983d958bbcSAppaRao Puli } 1199add6133bSRatan Gupta messages::success(asyncResp->res); 12003d958bbcSAppaRao Puli }, 12013d958bbcSAppaRao Puli "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user", 12023d958bbcSAppaRao Puli "org.freedesktop.DBus.Properties", "Set", 12033d958bbcSAppaRao Puli "xyz.openbmc_project.User.AccountPolicy", 1204abf2add6SEd Tanous "AccountUnlockTimeout", std::variant<uint32_t>(*unlockTimeout)); 12053d958bbcSAppaRao Puli } 12063d958bbcSAppaRao Puli if (lockoutThreshold) 12073d958bbcSAppaRao Puli { 12083d958bbcSAppaRao Puli crow::connections::systemBus->async_method_call( 12093d958bbcSAppaRao Puli [asyncResp](const boost::system::error_code ec) { 12103d958bbcSAppaRao Puli if (ec) 12113d958bbcSAppaRao Puli { 12123d958bbcSAppaRao Puli messages::internalError(asyncResp->res); 12133d958bbcSAppaRao Puli return; 12143d958bbcSAppaRao Puli } 1215add6133bSRatan Gupta messages::success(asyncResp->res); 12163d958bbcSAppaRao Puli }, 12173d958bbcSAppaRao Puli "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user", 12183d958bbcSAppaRao Puli "org.freedesktop.DBus.Properties", "Set", 12193d958bbcSAppaRao Puli "xyz.openbmc_project.User.AccountPolicy", 12203d958bbcSAppaRao Puli "MaxLoginAttemptBeforeLockout", 1221abf2add6SEd Tanous std::variant<uint16_t>(*lockoutThreshold)); 12223d958bbcSAppaRao Puli } 122388d16c9aSLewanczyk, Dawid } 122488d16c9aSLewanczyk, Dawid }; 1225f00032dbSTanous 1226b9b2e0b2SEd Tanous class AccountsCollection : public Node 1227b9b2e0b2SEd Tanous { 1228b9b2e0b2SEd Tanous public: 1229b9b2e0b2SEd Tanous AccountsCollection(CrowApp& app) : 1230b9b2e0b2SEd Tanous Node(app, "/redfish/v1/AccountService/Accounts/") 1231b9b2e0b2SEd Tanous { 1232b9b2e0b2SEd Tanous entityPrivileges = { 1233b9b2e0b2SEd Tanous {boost::beast::http::verb::get, 1234b9b2e0b2SEd Tanous {{"ConfigureUsers"}, {"ConfigureManager"}}}, 1235b9b2e0b2SEd Tanous {boost::beast::http::verb::head, {{"Login"}}}, 1236b9b2e0b2SEd Tanous {boost::beast::http::verb::patch, {{"ConfigureUsers"}}}, 1237b9b2e0b2SEd Tanous {boost::beast::http::verb::put, {{"ConfigureUsers"}}}, 1238b9b2e0b2SEd Tanous {boost::beast::http::verb::delete_, {{"ConfigureUsers"}}}, 1239b9b2e0b2SEd Tanous {boost::beast::http::verb::post, {{"ConfigureUsers"}}}}; 1240b9b2e0b2SEd Tanous } 1241b9b2e0b2SEd Tanous 1242b9b2e0b2SEd Tanous private: 1243b9b2e0b2SEd Tanous void doGet(crow::Response& res, const crow::Request& req, 1244b9b2e0b2SEd Tanous const std::vector<std::string>& params) override 1245b9b2e0b2SEd Tanous { 1246b9b2e0b2SEd Tanous auto asyncResp = std::make_shared<AsyncResp>(res); 12470f74e643SEd Tanous res.jsonValue = {{"@odata.context", 12480f74e643SEd Tanous "/redfish/v1/" 12490f74e643SEd Tanous "$metadata#ManagerAccountCollection." 12500f74e643SEd Tanous "ManagerAccountCollection"}, 12510f74e643SEd Tanous {"@odata.id", "/redfish/v1/AccountService/Accounts"}, 12520f74e643SEd Tanous {"@odata.type", "#ManagerAccountCollection." 12530f74e643SEd Tanous "ManagerAccountCollection"}, 12540f74e643SEd Tanous {"Name", "Accounts Collection"}, 12550f74e643SEd Tanous {"Description", "BMC User Accounts"}}; 12560f74e643SEd Tanous 1257b9b2e0b2SEd Tanous crow::connections::systemBus->async_method_call( 1258b9b2e0b2SEd Tanous [asyncResp](const boost::system::error_code ec, 1259b9b2e0b2SEd Tanous const ManagedObjectType& users) { 1260b9b2e0b2SEd Tanous if (ec) 1261b9b2e0b2SEd Tanous { 1262f12894f8SJason M. Bills messages::internalError(asyncResp->res); 1263b9b2e0b2SEd Tanous return; 1264b9b2e0b2SEd Tanous } 1265b9b2e0b2SEd Tanous 1266b9b2e0b2SEd Tanous nlohmann::json& memberArray = 1267b9b2e0b2SEd Tanous asyncResp->res.jsonValue["Members"]; 1268b9b2e0b2SEd Tanous memberArray = nlohmann::json::array(); 1269b9b2e0b2SEd Tanous 1270b9b2e0b2SEd Tanous asyncResp->res.jsonValue["Members@odata.count"] = users.size(); 1271b9b2e0b2SEd Tanous for (auto& user : users) 1272b9b2e0b2SEd Tanous { 1273b9b2e0b2SEd Tanous const std::string& path = 1274b9b2e0b2SEd Tanous static_cast<const std::string&>(user.first); 1275b9b2e0b2SEd Tanous std::size_t lastIndex = path.rfind("/"); 1276b9b2e0b2SEd Tanous if (lastIndex == std::string::npos) 1277b9b2e0b2SEd Tanous { 1278b9b2e0b2SEd Tanous lastIndex = 0; 1279b9b2e0b2SEd Tanous } 1280b9b2e0b2SEd Tanous else 1281b9b2e0b2SEd Tanous { 1282b9b2e0b2SEd Tanous lastIndex += 1; 1283b9b2e0b2SEd Tanous } 1284b9b2e0b2SEd Tanous memberArray.push_back( 1285b9b2e0b2SEd Tanous {{"@odata.id", "/redfish/v1/AccountService/Accounts/" + 1286b9b2e0b2SEd Tanous path.substr(lastIndex)}}); 1287b9b2e0b2SEd Tanous } 1288b9b2e0b2SEd Tanous }, 1289b9b2e0b2SEd Tanous "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user", 1290b9b2e0b2SEd Tanous "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 1291b9b2e0b2SEd Tanous } 129204ae99ecSEd Tanous void doPost(crow::Response& res, const crow::Request& req, 129304ae99ecSEd Tanous const std::vector<std::string>& params) override 129404ae99ecSEd Tanous { 129504ae99ecSEd Tanous auto asyncResp = std::make_shared<AsyncResp>(res); 129604ae99ecSEd Tanous 12979712f8acSEd Tanous std::string username; 12989712f8acSEd Tanous std::string password; 1299a24526dcSEd Tanous std::optional<std::string> roleId("User"); 1300a24526dcSEd Tanous std::optional<bool> enabled = true; 13019712f8acSEd Tanous if (!json_util::readJson(req, res, "UserName", username, "Password", 13029712f8acSEd Tanous password, "RoleId", roleId, "Enabled", 13039712f8acSEd Tanous enabled)) 130404ae99ecSEd Tanous { 130504ae99ecSEd Tanous return; 130604ae99ecSEd Tanous } 130704ae99ecSEd Tanous 130854fc587aSNagaraju Goruganti std::string priv = getPrivilegeFromRoleId(*roleId); 130984e12cb7SAppaRao Puli if (priv.empty()) 131004ae99ecSEd Tanous { 1311f12894f8SJason M. Bills messages::propertyValueNotInList(asyncResp->res, *roleId, "RoleId"); 131204ae99ecSEd Tanous return; 131304ae99ecSEd Tanous } 13149712f8acSEd Tanous roleId = priv; 131504ae99ecSEd Tanous 1316599c71d8SAyushi Smriti // Reading AllGroups property 1317599c71d8SAyushi Smriti crow::connections::systemBus->async_method_call( 1318599c71d8SAyushi Smriti [asyncResp, username, password{std::move(password)}, roleId, 1319599c71d8SAyushi Smriti enabled](const boost::system::error_code ec, 1320599c71d8SAyushi Smriti const std::variant<std::vector<std::string>>& allGroups) { 1321599c71d8SAyushi Smriti if (ec) 1322599c71d8SAyushi Smriti { 1323599c71d8SAyushi Smriti BMCWEB_LOG_DEBUG << "ERROR with async_method_call"; 1324599c71d8SAyushi Smriti messages::internalError(asyncResp->res); 1325599c71d8SAyushi Smriti return; 1326599c71d8SAyushi Smriti } 1327599c71d8SAyushi Smriti 1328599c71d8SAyushi Smriti const std::vector<std::string>* allGroupsList = 1329599c71d8SAyushi Smriti std::get_if<std::vector<std::string>>(&allGroups); 1330599c71d8SAyushi Smriti 1331599c71d8SAyushi Smriti if (allGroupsList == nullptr || allGroupsList->empty()) 1332599c71d8SAyushi Smriti { 1333599c71d8SAyushi Smriti messages::internalError(asyncResp->res); 1334599c71d8SAyushi Smriti return; 1335599c71d8SAyushi Smriti } 1336599c71d8SAyushi Smriti 133704ae99ecSEd Tanous crow::connections::systemBus->async_method_call( 13389712f8acSEd Tanous [asyncResp, username, password{std::move(password)}]( 133904ae99ecSEd Tanous const boost::system::error_code ec) { 134004ae99ecSEd Tanous if (ec) 134104ae99ecSEd Tanous { 134204ae99ecSEd Tanous messages::resourceAlreadyExists( 1343599c71d8SAyushi Smriti asyncResp->res, 1344599c71d8SAyushi Smriti "#ManagerAccount.v1_0_3.ManagerAccount", 1345f12894f8SJason M. Bills "UserName", username); 134604ae99ecSEd Tanous return; 134704ae99ecSEd Tanous } 134804ae99ecSEd Tanous 1349*66b5ca76Sjayaprakash Mutyala if (pamUpdatePassword(username, password) != 1350*66b5ca76Sjayaprakash Mutyala PAM_SUCCESS) 135104ae99ecSEd Tanous { 1352599c71d8SAyushi Smriti // At this point we have a user that's been created, 1353599c71d8SAyushi Smriti // but the password set failed.Something is wrong, 1354599c71d8SAyushi Smriti // so delete the user that we've already created 135504ae99ecSEd Tanous crow::connections::systemBus->async_method_call( 1356599c71d8SAyushi Smriti [asyncResp]( 1357599c71d8SAyushi Smriti const boost::system::error_code ec) { 135804ae99ecSEd Tanous if (ec) 135904ae99ecSEd Tanous { 1360f12894f8SJason M. Bills messages::internalError(asyncResp->res); 136104ae99ecSEd Tanous return; 136204ae99ecSEd Tanous } 136304ae99ecSEd Tanous 1364599c71d8SAyushi Smriti messages::invalidObject(asyncResp->res, 1365599c71d8SAyushi Smriti "Password"); 136604ae99ecSEd Tanous }, 136704ae99ecSEd Tanous "xyz.openbmc_project.User.Manager", 136804ae99ecSEd Tanous "/xyz/openbmc_project/user/" + username, 136904ae99ecSEd Tanous "xyz.openbmc_project.Object.Delete", "Delete"); 137004ae99ecSEd Tanous 137104ae99ecSEd Tanous BMCWEB_LOG_ERROR << "pamUpdatePassword Failed"; 137204ae99ecSEd Tanous return; 137304ae99ecSEd Tanous } 137404ae99ecSEd Tanous 1375f12894f8SJason M. Bills messages::created(asyncResp->res); 137604ae99ecSEd Tanous asyncResp->res.addHeader( 137704ae99ecSEd Tanous "Location", 137804ae99ecSEd Tanous "/redfish/v1/AccountService/Accounts/" + username); 137904ae99ecSEd Tanous }, 1380599c71d8SAyushi Smriti "xyz.openbmc_project.User.Manager", 1381599c71d8SAyushi Smriti "/xyz/openbmc_project/user", 13829712f8acSEd Tanous "xyz.openbmc_project.User.Manager", "CreateUser", username, 1383599c71d8SAyushi Smriti *allGroupsList, *roleId, *enabled); 1384599c71d8SAyushi Smriti }, 1385599c71d8SAyushi Smriti "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user", 1386599c71d8SAyushi Smriti "org.freedesktop.DBus.Properties", "Get", 1387599c71d8SAyushi Smriti "xyz.openbmc_project.User.Manager", "AllGroups"); 138804ae99ecSEd Tanous } 1389b9b2e0b2SEd Tanous }; 1390b9b2e0b2SEd Tanous 1391b9b2e0b2SEd Tanous class ManagerAccount : public Node 1392b9b2e0b2SEd Tanous { 1393b9b2e0b2SEd Tanous public: 1394b9b2e0b2SEd Tanous ManagerAccount(CrowApp& app) : 1395b9b2e0b2SEd Tanous Node(app, "/redfish/v1/AccountService/Accounts/<str>/", std::string()) 1396b9b2e0b2SEd Tanous { 1397b9b2e0b2SEd Tanous entityPrivileges = { 1398b9b2e0b2SEd Tanous {boost::beast::http::verb::get, 1399b9b2e0b2SEd Tanous {{"ConfigureUsers"}, {"ConfigureManager"}, {"ConfigureSelf"}}}, 1400b9b2e0b2SEd Tanous {boost::beast::http::verb::head, {{"Login"}}}, 1401b9b2e0b2SEd Tanous {boost::beast::http::verb::patch, {{"ConfigureUsers"}}}, 1402b9b2e0b2SEd Tanous {boost::beast::http::verb::put, {{"ConfigureUsers"}}}, 1403b9b2e0b2SEd Tanous {boost::beast::http::verb::delete_, {{"ConfigureUsers"}}}, 1404b9b2e0b2SEd Tanous {boost::beast::http::verb::post, {{"ConfigureUsers"}}}}; 1405b9b2e0b2SEd Tanous } 1406b9b2e0b2SEd Tanous 1407b9b2e0b2SEd Tanous private: 1408b9b2e0b2SEd Tanous void doGet(crow::Response& res, const crow::Request& req, 1409b9b2e0b2SEd Tanous const std::vector<std::string>& params) override 1410b9b2e0b2SEd Tanous { 14110f74e643SEd Tanous 1412b9b2e0b2SEd Tanous auto asyncResp = std::make_shared<AsyncResp>(res); 1413b9b2e0b2SEd Tanous 1414b9b2e0b2SEd Tanous if (params.size() != 1) 1415b9b2e0b2SEd Tanous { 1416f12894f8SJason M. Bills messages::internalError(asyncResp->res); 1417b9b2e0b2SEd Tanous return; 1418b9b2e0b2SEd Tanous } 1419b9b2e0b2SEd Tanous 1420b9b2e0b2SEd Tanous crow::connections::systemBus->async_method_call( 1421b9b2e0b2SEd Tanous [asyncResp, accountName{std::string(params[0])}]( 1422b9b2e0b2SEd Tanous const boost::system::error_code ec, 1423b9b2e0b2SEd Tanous const ManagedObjectType& users) { 1424b9b2e0b2SEd Tanous if (ec) 1425b9b2e0b2SEd Tanous { 1426f12894f8SJason M. Bills messages::internalError(asyncResp->res); 1427b9b2e0b2SEd Tanous return; 1428b9b2e0b2SEd Tanous } 142984e12cb7SAppaRao Puli auto userIt = users.begin(); 1430b9b2e0b2SEd Tanous 143184e12cb7SAppaRao Puli for (; userIt != users.end(); userIt++) 1432b9b2e0b2SEd Tanous { 143384e12cb7SAppaRao Puli if (boost::ends_with(userIt->first.str, "/" + accountName)) 1434b9b2e0b2SEd Tanous { 143584e12cb7SAppaRao Puli break; 1436b9b2e0b2SEd Tanous } 1437b9b2e0b2SEd Tanous } 143884e12cb7SAppaRao Puli if (userIt == users.end()) 1439b9b2e0b2SEd Tanous { 144084e12cb7SAppaRao Puli messages::resourceNotFound(asyncResp->res, "ManagerAccount", 144184e12cb7SAppaRao Puli accountName); 144284e12cb7SAppaRao Puli return; 144384e12cb7SAppaRao Puli } 14444e68c45bSAyushi Smriti 14454e68c45bSAyushi Smriti asyncResp->res.jsonValue = { 14464e68c45bSAyushi Smriti {"@odata.context", 14474e68c45bSAyushi Smriti "/redfish/v1/$metadata#ManagerAccount.ManagerAccount"}, 14484e68c45bSAyushi Smriti {"@odata.type", "#ManagerAccount.v1_0_3.ManagerAccount"}, 14494e68c45bSAyushi Smriti {"Name", "User Account"}, 14504e68c45bSAyushi Smriti {"Description", "User Account"}, 14514e68c45bSAyushi Smriti {"Password", nullptr}}; 14524e68c45bSAyushi Smriti 145384e12cb7SAppaRao Puli for (const auto& interface : userIt->second) 145465b0dc32SEd Tanous { 145565b0dc32SEd Tanous if (interface.first == 145665b0dc32SEd Tanous "xyz.openbmc_project.User.Attributes") 145765b0dc32SEd Tanous { 145865b0dc32SEd Tanous for (const auto& property : interface.second) 145965b0dc32SEd Tanous { 146065b0dc32SEd Tanous if (property.first == "UserEnabled") 146165b0dc32SEd Tanous { 146265b0dc32SEd Tanous const bool* userEnabled = 1463abf2add6SEd Tanous std::get_if<bool>(&property.second); 146465b0dc32SEd Tanous if (userEnabled == nullptr) 146565b0dc32SEd Tanous { 146665b0dc32SEd Tanous BMCWEB_LOG_ERROR 146765b0dc32SEd Tanous << "UserEnabled wasn't a bool"; 146884e12cb7SAppaRao Puli messages::internalError(asyncResp->res); 146984e12cb7SAppaRao Puli return; 147065b0dc32SEd Tanous } 147165b0dc32SEd Tanous asyncResp->res.jsonValue["Enabled"] = 147265b0dc32SEd Tanous *userEnabled; 147365b0dc32SEd Tanous } 147465b0dc32SEd Tanous else if (property.first == 147565b0dc32SEd Tanous "UserLockedForFailedAttempt") 147665b0dc32SEd Tanous { 147765b0dc32SEd Tanous const bool* userLocked = 1478abf2add6SEd Tanous std::get_if<bool>(&property.second); 147965b0dc32SEd Tanous if (userLocked == nullptr) 148065b0dc32SEd Tanous { 148184e12cb7SAppaRao Puli BMCWEB_LOG_ERROR << "UserLockedForF" 148284e12cb7SAppaRao Puli "ailedAttempt " 148384e12cb7SAppaRao Puli "wasn't a bool"; 148484e12cb7SAppaRao Puli messages::internalError(asyncResp->res); 148584e12cb7SAppaRao Puli return; 148665b0dc32SEd Tanous } 148765b0dc32SEd Tanous asyncResp->res.jsonValue["Locked"] = 148865b0dc32SEd Tanous *userLocked; 148924c8542dSRatan Gupta asyncResp->res.jsonValue 149024c8542dSRatan Gupta ["Locked@Redfish.AllowableValues"] = { 14914d64ce34SGunnar Mills "false"}; 149265b0dc32SEd Tanous } 149384e12cb7SAppaRao Puli else if (property.first == "UserPrivilege") 149484e12cb7SAppaRao Puli { 149554fc587aSNagaraju Goruganti const std::string* userPrivPtr = 1496abf2add6SEd Tanous std::get_if<std::string>(&property.second); 149754fc587aSNagaraju Goruganti if (userPrivPtr == nullptr) 149884e12cb7SAppaRao Puli { 149984e12cb7SAppaRao Puli BMCWEB_LOG_ERROR 150084e12cb7SAppaRao Puli << "UserPrivilege wasn't a " 150184e12cb7SAppaRao Puli "string"; 150284e12cb7SAppaRao Puli messages::internalError(asyncResp->res); 150384e12cb7SAppaRao Puli return; 150484e12cb7SAppaRao Puli } 150554fc587aSNagaraju Goruganti std::string role = 150654fc587aSNagaraju Goruganti getRoleIdFromPrivilege(*userPrivPtr); 150754fc587aSNagaraju Goruganti if (role.empty()) 150884e12cb7SAppaRao Puli { 150984e12cb7SAppaRao Puli BMCWEB_LOG_ERROR << "Invalid user role"; 151084e12cb7SAppaRao Puli messages::internalError(asyncResp->res); 151184e12cb7SAppaRao Puli return; 151284e12cb7SAppaRao Puli } 151354fc587aSNagaraju Goruganti asyncResp->res.jsonValue["RoleId"] = role; 151484e12cb7SAppaRao Puli 151584e12cb7SAppaRao Puli asyncResp->res.jsonValue["Links"]["Role"] = { 151684e12cb7SAppaRao Puli {"@odata.id", "/redfish/v1/AccountService/" 151784e12cb7SAppaRao Puli "Roles/" + 151854fc587aSNagaraju Goruganti role}}; 151984e12cb7SAppaRao Puli } 152065b0dc32SEd Tanous } 152165b0dc32SEd Tanous } 152265b0dc32SEd Tanous } 152365b0dc32SEd Tanous 1524b9b2e0b2SEd Tanous asyncResp->res.jsonValue["@odata.id"] = 152584e12cb7SAppaRao Puli "/redfish/v1/AccountService/Accounts/" + accountName; 1526b9b2e0b2SEd Tanous asyncResp->res.jsonValue["Id"] = accountName; 1527b9b2e0b2SEd Tanous asyncResp->res.jsonValue["UserName"] = accountName; 1528b9b2e0b2SEd Tanous }, 1529b9b2e0b2SEd Tanous "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user", 1530b9b2e0b2SEd Tanous "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 1531b9b2e0b2SEd Tanous } 1532a840879dSEd Tanous 1533a840879dSEd Tanous void doPatch(crow::Response& res, const crow::Request& req, 1534a840879dSEd Tanous const std::vector<std::string>& params) override 1535a840879dSEd Tanous { 1536a840879dSEd Tanous auto asyncResp = std::make_shared<AsyncResp>(res); 1537a840879dSEd Tanous if (params.size() != 1) 1538a840879dSEd Tanous { 1539f12894f8SJason M. Bills messages::internalError(asyncResp->res); 1540a840879dSEd Tanous return; 1541a840879dSEd Tanous } 1542a840879dSEd Tanous 1543a24526dcSEd Tanous std::optional<std::string> newUserName; 1544a24526dcSEd Tanous std::optional<std::string> password; 1545a24526dcSEd Tanous std::optional<bool> enabled; 1546a24526dcSEd Tanous std::optional<std::string> roleId; 154724c8542dSRatan Gupta std::optional<bool> locked; 154884e12cb7SAppaRao Puli if (!json_util::readJson(req, res, "UserName", newUserName, "Password", 154924c8542dSRatan Gupta password, "RoleId", roleId, "Enabled", enabled, 155024c8542dSRatan Gupta "Locked", locked)) 1551a840879dSEd Tanous { 1552a840879dSEd Tanous return; 1553a840879dSEd Tanous } 1554a840879dSEd Tanous 155584e12cb7SAppaRao Puli const std::string& username = params[0]; 155684e12cb7SAppaRao Puli 1557*66b5ca76Sjayaprakash Mutyala // if user name is not provided in the patch method or if it 1558*66b5ca76Sjayaprakash Mutyala // matches the user name in the URI, then we are treating it as updating 1559*66b5ca76Sjayaprakash Mutyala // user properties other then username. If username provided doesn't 1560*66b5ca76Sjayaprakash Mutyala // match the URI, then we are treating this as user rename request. 1561*66b5ca76Sjayaprakash Mutyala if (!newUserName || (newUserName.value() == username)) 1562a840879dSEd Tanous { 156324c8542dSRatan Gupta updateUserProperties(asyncResp, username, password, enabled, roleId, 156424c8542dSRatan Gupta locked); 156584e12cb7SAppaRao Puli return; 156684e12cb7SAppaRao Puli } 156784e12cb7SAppaRao Puli else 156884e12cb7SAppaRao Puli { 156984e12cb7SAppaRao Puli crow::connections::systemBus->async_method_call( 157084e12cb7SAppaRao Puli [this, asyncResp, username, password(std::move(password)), 157184e12cb7SAppaRao Puli roleId(std::move(roleId)), enabled(std::move(enabled)), 1572*66b5ca76Sjayaprakash Mutyala newUser{std::string(*newUserName)}, 1573*66b5ca76Sjayaprakash Mutyala locked(std::move(locked))](const boost::system::error_code ec, 1574*66b5ca76Sjayaprakash Mutyala sdbusplus::message::message& m) { 157584e12cb7SAppaRao Puli if (ec) 157684e12cb7SAppaRao Puli { 1577*66b5ca76Sjayaprakash Mutyala userErrorMessageHandler(m.get_error(), asyncResp, 1578*66b5ca76Sjayaprakash Mutyala newUser, username); 1579a840879dSEd Tanous return; 1580a840879dSEd Tanous } 1581a840879dSEd Tanous 158284e12cb7SAppaRao Puli updateUserProperties(asyncResp, newUser, password, enabled, 158324c8542dSRatan Gupta roleId, locked); 158484e12cb7SAppaRao Puli }, 158584e12cb7SAppaRao Puli "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user", 158684e12cb7SAppaRao Puli "xyz.openbmc_project.User.Manager", "RenameUser", username, 158784e12cb7SAppaRao Puli *newUserName); 158884e12cb7SAppaRao Puli } 158984e12cb7SAppaRao Puli } 159084e12cb7SAppaRao Puli 159184e12cb7SAppaRao Puli void updateUserProperties(std::shared_ptr<AsyncResp> asyncResp, 159284e12cb7SAppaRao Puli const std::string& username, 1593a24526dcSEd Tanous std::optional<std::string> password, 1594a24526dcSEd Tanous std::optional<bool> enabled, 159524c8542dSRatan Gupta std::optional<std::string> roleId, 159624c8542dSRatan Gupta std::optional<bool> locked) 159784e12cb7SAppaRao Puli { 159824c8542dSRatan Gupta std::string dbusObjectPath = "/xyz/openbmc_project/user/" + username; 159924c8542dSRatan Gupta dbus::utility::escapePathForDbus(dbusObjectPath); 160024c8542dSRatan Gupta 160122c33710SRatan Gupta dbus::utility::checkDbusPathExists( 160224c8542dSRatan Gupta dbusObjectPath, 160324c8542dSRatan Gupta [dbusObjectPath(std::move(dbusObjectPath)), username, 160424c8542dSRatan Gupta password(std::move(password)), roleId(std::move(roleId)), 160524c8542dSRatan Gupta enabled(std::move(enabled)), locked(std::move(locked)), 160624c8542dSRatan Gupta asyncResp{std::move(asyncResp)}](int rc) { 160724c8542dSRatan Gupta if (!rc) 160824c8542dSRatan Gupta { 1609*66b5ca76Sjayaprakash Mutyala messages::resourceNotFound( 1610*66b5ca76Sjayaprakash Mutyala asyncResp->res, "#ManagerAccount.v1_0_3.ManagerAccount", 1611*66b5ca76Sjayaprakash Mutyala username); 161224c8542dSRatan Gupta return; 161324c8542dSRatan Gupta } 1614*66b5ca76Sjayaprakash Mutyala 1615*66b5ca76Sjayaprakash Mutyala if (password) 1616*66b5ca76Sjayaprakash Mutyala { 1617*66b5ca76Sjayaprakash Mutyala int retval = pamUpdatePassword(username, *password); 1618*66b5ca76Sjayaprakash Mutyala 1619*66b5ca76Sjayaprakash Mutyala if (retval == PAM_USER_UNKNOWN) 1620*66b5ca76Sjayaprakash Mutyala { 1621*66b5ca76Sjayaprakash Mutyala messages::resourceNotFound( 1622*66b5ca76Sjayaprakash Mutyala asyncResp->res, 1623*66b5ca76Sjayaprakash Mutyala "#ManagerAccount.v1_0_3.ManagerAccount", username); 1624*66b5ca76Sjayaprakash Mutyala } 1625*66b5ca76Sjayaprakash Mutyala else if (retval == PAM_AUTHTOK_ERR) 1626*66b5ca76Sjayaprakash Mutyala { 1627*66b5ca76Sjayaprakash Mutyala // If password is invalid 1628*66b5ca76Sjayaprakash Mutyala messages::propertyValueFormatError( 1629*66b5ca76Sjayaprakash Mutyala asyncResp->res, *password, "Password"); 1630*66b5ca76Sjayaprakash Mutyala BMCWEB_LOG_ERROR << "pamUpdatePassword Failed"; 1631*66b5ca76Sjayaprakash Mutyala } 1632*66b5ca76Sjayaprakash Mutyala else if (retval != PAM_SUCCESS) 1633*66b5ca76Sjayaprakash Mutyala { 1634*66b5ca76Sjayaprakash Mutyala messages::internalError(asyncResp->res); 1635*66b5ca76Sjayaprakash Mutyala return; 1636*66b5ca76Sjayaprakash Mutyala } 1637*66b5ca76Sjayaprakash Mutyala } 1638*66b5ca76Sjayaprakash Mutyala 16399712f8acSEd Tanous if (enabled) 1640a840879dSEd Tanous { 1641a840879dSEd Tanous crow::connections::systemBus->async_method_call( 1642a840879dSEd Tanous [asyncResp](const boost::system::error_code ec) { 1643a840879dSEd Tanous if (ec) 1644a840879dSEd Tanous { 164524c8542dSRatan Gupta BMCWEB_LOG_ERROR << "D-Bus responses error: " 164624c8542dSRatan Gupta << ec; 1647f12894f8SJason M. Bills messages::internalError(asyncResp->res); 1648a840879dSEd Tanous return; 1649a840879dSEd Tanous } 165084e12cb7SAppaRao Puli messages::success(asyncResp->res); 165184e12cb7SAppaRao Puli return; 165284e12cb7SAppaRao Puli }, 165384e12cb7SAppaRao Puli "xyz.openbmc_project.User.Manager", 165424c8542dSRatan Gupta dbusObjectPath.c_str(), 165584e12cb7SAppaRao Puli "org.freedesktop.DBus.Properties", "Set", 165684e12cb7SAppaRao Puli "xyz.openbmc_project.User.Attributes", "UserEnabled", 1657abf2add6SEd Tanous std::variant<bool>{*enabled}); 165884e12cb7SAppaRao Puli } 165984e12cb7SAppaRao Puli 166084e12cb7SAppaRao Puli if (roleId) 166184e12cb7SAppaRao Puli { 166254fc587aSNagaraju Goruganti std::string priv = getPrivilegeFromRoleId(*roleId); 166384e12cb7SAppaRao Puli if (priv.empty()) 166484e12cb7SAppaRao Puli { 166524c8542dSRatan Gupta messages::propertyValueNotInList(asyncResp->res, 166624c8542dSRatan Gupta *roleId, "RoleId"); 166784e12cb7SAppaRao Puli return; 166884e12cb7SAppaRao Puli } 166984e12cb7SAppaRao Puli 167084e12cb7SAppaRao Puli crow::connections::systemBus->async_method_call( 167184e12cb7SAppaRao Puli [asyncResp](const boost::system::error_code ec) { 167284e12cb7SAppaRao Puli if (ec) 167384e12cb7SAppaRao Puli { 167424c8542dSRatan Gupta BMCWEB_LOG_ERROR << "D-Bus responses error: " 167524c8542dSRatan Gupta << ec; 167684e12cb7SAppaRao Puli messages::internalError(asyncResp->res); 167784e12cb7SAppaRao Puli return; 167884e12cb7SAppaRao Puli } 1679f12894f8SJason M. Bills messages::success(asyncResp->res); 1680a840879dSEd Tanous }, 1681a840879dSEd Tanous "xyz.openbmc_project.User.Manager", 168224c8542dSRatan Gupta dbusObjectPath.c_str(), 1683a840879dSEd Tanous "org.freedesktop.DBus.Properties", "Set", 168484e12cb7SAppaRao Puli "xyz.openbmc_project.User.Attributes", "UserPrivilege", 1685abf2add6SEd Tanous std::variant<std::string>{priv}); 1686a840879dSEd Tanous } 168724c8542dSRatan Gupta 168824c8542dSRatan Gupta if (locked) 168924c8542dSRatan Gupta { 169024c8542dSRatan Gupta // admin can unlock the account which is locked by 169154fc587aSNagaraju Goruganti // successive authentication failures but admin should 169254fc587aSNagaraju Goruganti // not be allowed to lock an account. 169324c8542dSRatan Gupta if (*locked) 169424c8542dSRatan Gupta { 169524c8542dSRatan Gupta messages::propertyValueNotInList(asyncResp->res, "true", 169624c8542dSRatan Gupta "Locked"); 169724c8542dSRatan Gupta return; 169824c8542dSRatan Gupta } 169924c8542dSRatan Gupta 170024c8542dSRatan Gupta crow::connections::systemBus->async_method_call( 170124c8542dSRatan Gupta [asyncResp](const boost::system::error_code ec) { 170224c8542dSRatan Gupta if (ec) 170324c8542dSRatan Gupta { 170424c8542dSRatan Gupta BMCWEB_LOG_ERROR << "D-Bus responses error: " 170524c8542dSRatan Gupta << ec; 170624c8542dSRatan Gupta messages::internalError(asyncResp->res); 170724c8542dSRatan Gupta return; 170824c8542dSRatan Gupta } 170924c8542dSRatan Gupta messages::success(asyncResp->res); 171024c8542dSRatan Gupta return; 171124c8542dSRatan Gupta }, 171224c8542dSRatan Gupta "xyz.openbmc_project.User.Manager", 171324c8542dSRatan Gupta dbusObjectPath.c_str(), 171424c8542dSRatan Gupta "org.freedesktop.DBus.Properties", "Set", 171524c8542dSRatan Gupta "xyz.openbmc_project.User.Attributes", 171624c8542dSRatan Gupta "UserLockedForFailedAttempt", 171724c8542dSRatan Gupta sdbusplus::message::variant<bool>{*locked}); 171824c8542dSRatan Gupta } 171924c8542dSRatan Gupta }); 1720a840879dSEd Tanous } 172106e086d9SEd Tanous 172206e086d9SEd Tanous void doDelete(crow::Response& res, const crow::Request& req, 172306e086d9SEd Tanous const std::vector<std::string>& params) override 172406e086d9SEd Tanous { 172506e086d9SEd Tanous auto asyncResp = std::make_shared<AsyncResp>(res); 172606e086d9SEd Tanous 172706e086d9SEd Tanous if (params.size() != 1) 172806e086d9SEd Tanous { 1729f12894f8SJason M. Bills messages::internalError(asyncResp->res); 173006e086d9SEd Tanous return; 173106e086d9SEd Tanous } 173206e086d9SEd Tanous 173306e086d9SEd Tanous const std::string userPath = "/xyz/openbmc_project/user/" + params[0]; 173406e086d9SEd Tanous 173506e086d9SEd Tanous crow::connections::systemBus->async_method_call( 173606e086d9SEd Tanous [asyncResp, username{std::move(params[0])}]( 173706e086d9SEd Tanous const boost::system::error_code ec) { 173806e086d9SEd Tanous if (ec) 173906e086d9SEd Tanous { 174006e086d9SEd Tanous messages::resourceNotFound( 1741f12894f8SJason M. Bills asyncResp->res, "#ManagerAccount.v1_0_3.ManagerAccount", 1742f12894f8SJason M. Bills username); 174306e086d9SEd Tanous return; 174406e086d9SEd Tanous } 174506e086d9SEd Tanous 1746f12894f8SJason M. Bills messages::accountRemoved(asyncResp->res); 174706e086d9SEd Tanous }, 174806e086d9SEd Tanous "xyz.openbmc_project.User.Manager", userPath, 174906e086d9SEd Tanous "xyz.openbmc_project.Object.Delete", "Delete"); 175006e086d9SEd Tanous } 175184e12cb7SAppaRao Puli }; 175288d16c9aSLewanczyk, Dawid 175388d16c9aSLewanczyk, Dawid } // namespace redfish 1754