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 28*6973a582SRatan Gupta constexpr const char* ldapConfigObject = 29*6973a582SRatan Gupta "/xyz/openbmc_project/user/ldap/openldap"; 30*6973a582SRatan Gupta constexpr const char* ldapRootObject = "/xyz/openbmc_project/user/ldap"; 31*6973a582SRatan Gupta constexpr const char* ldapDbusService = "xyz.openbmc_project.Ldap.Config"; 32*6973a582SRatan Gupta constexpr const char* ldapConfigInterface = 33*6973a582SRatan Gupta "xyz.openbmc_project.User.Ldap.Config"; 34*6973a582SRatan Gupta constexpr const char* ldapCreateInterface = 35*6973a582SRatan Gupta "xyz.openbmc_project.User.Ldap.Create"; 36*6973a582SRatan Gupta constexpr const char* ldapEnableInterface = "xyz.openbmc_project.Object.Enable"; 37*6973a582SRatan Gupta constexpr const char* dbusObjManagerIntf = "org.freedesktop.DBus.ObjectManager"; 38*6973a582SRatan Gupta constexpr const char* propertyInterface = "org.freedesktop.DBus.Properties"; 39*6973a582SRatan Gupta constexpr const char* mapperBusName = "xyz.openbmc_project.ObjectMapper"; 40*6973a582SRatan Gupta constexpr const char* mapperObjectPath = "/xyz/openbmc_project/object_mapper"; 41*6973a582SRatan Gupta constexpr const char* mapperIntf = "xyz.openbmc_project.ObjectMapper"; 42*6973a582SRatan Gupta 43*6973a582SRatan Gupta struct LDAPConfigData 44*6973a582SRatan Gupta { 45*6973a582SRatan Gupta std::string uri{}; 46*6973a582SRatan Gupta std::string bindDN{}; 47*6973a582SRatan Gupta std::string baseDN{}; 48*6973a582SRatan Gupta std::string searchScope{}; 49*6973a582SRatan Gupta std::string serverType{}; 50*6973a582SRatan Gupta bool serviceEnabled = false; 51*6973a582SRatan Gupta std::string userNameAttribute{}; 52*6973a582SRatan Gupta std::string groupAttribute{}; 53*6973a582SRatan Gupta }; 54*6973a582SRatan Gupta 55b9b2e0b2SEd Tanous using ManagedObjectType = std::vector<std::pair< 56b9b2e0b2SEd Tanous sdbusplus::message::object_path, 57b9b2e0b2SEd Tanous boost::container::flat_map< 58abf2add6SEd Tanous std::string, boost::container::flat_map< 59abf2add6SEd Tanous std::string, std::variant<bool, std::string>>>>>; 60*6973a582SRatan Gupta using GetObjectType = 61*6973a582SRatan Gupta std::vector<std::pair<std::string, std::vector<std::string>>>; 6284e12cb7SAppaRao Puli 63ae29b8c4SAdriana Kobylak inline std::string getPrivilegeFromRoleId(std::string_view role) 6484e12cb7SAppaRao Puli { 6584e12cb7SAppaRao Puli if (role == "priv-admin") 6684e12cb7SAppaRao Puli { 6784e12cb7SAppaRao Puli return "Administrator"; 6884e12cb7SAppaRao Puli } 6984e12cb7SAppaRao Puli else if (role == "priv-callback") 7084e12cb7SAppaRao Puli { 7184e12cb7SAppaRao Puli return "Callback"; 7284e12cb7SAppaRao Puli } 7384e12cb7SAppaRao Puli else if (role == "priv-user") 7484e12cb7SAppaRao Puli { 7584e12cb7SAppaRao Puli return "User"; 7684e12cb7SAppaRao Puli } 7784e12cb7SAppaRao Puli else if (role == "priv-operator") 7884e12cb7SAppaRao Puli { 7984e12cb7SAppaRao Puli return "Operator"; 8084e12cb7SAppaRao Puli } 8184e12cb7SAppaRao Puli return ""; 8284e12cb7SAppaRao Puli } 83ae29b8c4SAdriana Kobylak inline std::string getRoleIdFromPrivilege(std::string_view role) 8484e12cb7SAppaRao Puli { 8584e12cb7SAppaRao Puli if (role == "Administrator") 8684e12cb7SAppaRao Puli { 8784e12cb7SAppaRao Puli return "priv-admin"; 8884e12cb7SAppaRao Puli } 8984e12cb7SAppaRao Puli else if (role == "Callback") 9084e12cb7SAppaRao Puli { 9184e12cb7SAppaRao Puli return "priv-callback"; 9284e12cb7SAppaRao Puli } 9384e12cb7SAppaRao Puli else if (role == "User") 9484e12cb7SAppaRao Puli { 9584e12cb7SAppaRao Puli return "priv-user"; 9684e12cb7SAppaRao Puli } 9784e12cb7SAppaRao Puli else if (role == "Operator") 9884e12cb7SAppaRao Puli { 9984e12cb7SAppaRao Puli return "priv-operator"; 10084e12cb7SAppaRao Puli } 10184e12cb7SAppaRao Puli return ""; 10284e12cb7SAppaRao Puli } 103b9b2e0b2SEd Tanous 104*6973a582SRatan Gupta void parseLDAPConfigData(nlohmann::json& json_response, 105*6973a582SRatan Gupta const LDAPConfigData& confData) 106*6973a582SRatan Gupta { 107*6973a582SRatan Gupta std::string service = "LDAPService"; 108*6973a582SRatan Gupta json_response["LDAP"] = { 109*6973a582SRatan Gupta {"AccountProviderType", service}, 110*6973a582SRatan Gupta {"AccountProviderType@Redfish.AllowableValues", 111*6973a582SRatan Gupta nlohmann::json::array({service})}, 112*6973a582SRatan Gupta {"ServiceEnabled", confData.serviceEnabled}, 113*6973a582SRatan Gupta {"ServiceAddresses", nlohmann::json::array({confData.uri})}, 114*6973a582SRatan Gupta {"Authentication", 115*6973a582SRatan Gupta {{"AuthenticationType", "UsernameAndPassword"}, 116*6973a582SRatan Gupta {"AuthenticationType@Redfish.AllowableValues", 117*6973a582SRatan Gupta nlohmann::json::array({"UsernameAndPassword"})}, 118*6973a582SRatan Gupta {"Username", confData.bindDN}, 119*6973a582SRatan Gupta {"Password", nullptr}}}, 120*6973a582SRatan Gupta {"LDAPService", 121*6973a582SRatan Gupta {{"SearchSettings", 122*6973a582SRatan Gupta {{"BaseDistinguishedNames", 123*6973a582SRatan Gupta nlohmann::json::array({confData.baseDN})}, 124*6973a582SRatan Gupta {"UsernameAttribute", confData.userNameAttribute}, 125*6973a582SRatan Gupta {"GroupsAttribute", confData.groupAttribute}}}}}, 126*6973a582SRatan Gupta }; 127*6973a582SRatan Gupta } 128*6973a582SRatan Gupta 129*6973a582SRatan Gupta /** 130*6973a582SRatan Gupta * Function that retrieves all properties for LDAP config object 131*6973a582SRatan Gupta * into JSON 132*6973a582SRatan Gupta */ 133*6973a582SRatan Gupta template <typename CallbackFunc> 134*6973a582SRatan Gupta inline void getLDAPConfigData(const std::string& ldapType, 135*6973a582SRatan Gupta CallbackFunc&& callback) 136*6973a582SRatan Gupta { 137*6973a582SRatan Gupta auto getConfig = [callback, 138*6973a582SRatan Gupta ldapType](const boost::system::error_code error_code, 139*6973a582SRatan Gupta const ManagedObjectType& ldapObjects) { 140*6973a582SRatan Gupta LDAPConfigData confData{}; 141*6973a582SRatan Gupta if (error_code) 142*6973a582SRatan Gupta { 143*6973a582SRatan Gupta callback(false, confData); 144*6973a582SRatan Gupta BMCWEB_LOG_ERROR << "D-Bus responses error: " << error_code; 145*6973a582SRatan Gupta return; 146*6973a582SRatan Gupta } 147*6973a582SRatan Gupta std::string ldapConfigObjectStr = std::string(ldapConfigObject); 148*6973a582SRatan Gupta std::string ldapEnableInterfaceStr = std::string(ldapEnableInterface); 149*6973a582SRatan Gupta std::string ldapConfigInterfaceStr = std::string(ldapConfigInterface); 150*6973a582SRatan Gupta for (const auto& object : ldapObjects) 151*6973a582SRatan Gupta { 152*6973a582SRatan Gupta if (object.first == ldapConfigObjectStr) 153*6973a582SRatan Gupta { 154*6973a582SRatan Gupta for (const auto& interface : object.second) 155*6973a582SRatan Gupta { 156*6973a582SRatan Gupta if (interface.first == ldapEnableInterfaceStr) 157*6973a582SRatan Gupta { 158*6973a582SRatan Gupta // rest of the properties are string. 159*6973a582SRatan Gupta for (const auto& property : interface.second) 160*6973a582SRatan Gupta { 161*6973a582SRatan Gupta if (property.first == "Enabled") 162*6973a582SRatan Gupta { 163*6973a582SRatan Gupta const bool* value = 164*6973a582SRatan Gupta std::get_if<bool>(&property.second); 165*6973a582SRatan Gupta if (value == nullptr) 166*6973a582SRatan Gupta { 167*6973a582SRatan Gupta continue; 168*6973a582SRatan Gupta } 169*6973a582SRatan Gupta confData.serviceEnabled = *value; 170*6973a582SRatan Gupta break; 171*6973a582SRatan Gupta } 172*6973a582SRatan Gupta } 173*6973a582SRatan Gupta } 174*6973a582SRatan Gupta else if (interface.first == ldapConfigInterfaceStr) 175*6973a582SRatan Gupta { 176*6973a582SRatan Gupta 177*6973a582SRatan Gupta for (const auto& property : interface.second) 178*6973a582SRatan Gupta { 179*6973a582SRatan Gupta const std::string* value = 180*6973a582SRatan Gupta std::get_if<std::string>(&property.second); 181*6973a582SRatan Gupta if (value == nullptr) 182*6973a582SRatan Gupta { 183*6973a582SRatan Gupta continue; 184*6973a582SRatan Gupta } 185*6973a582SRatan Gupta if (property.first == "LDAPServerURI") 186*6973a582SRatan Gupta { 187*6973a582SRatan Gupta confData.uri = *value; 188*6973a582SRatan Gupta } 189*6973a582SRatan Gupta else if (property.first == "LDAPBindDN") 190*6973a582SRatan Gupta { 191*6973a582SRatan Gupta confData.bindDN = *value; 192*6973a582SRatan Gupta } 193*6973a582SRatan Gupta else if (property.first == "LDAPBaseDN") 194*6973a582SRatan Gupta { 195*6973a582SRatan Gupta confData.baseDN = *value; 196*6973a582SRatan Gupta } 197*6973a582SRatan Gupta else if (property.first == "LDAPSearchScope") 198*6973a582SRatan Gupta { 199*6973a582SRatan Gupta confData.searchScope = *value; 200*6973a582SRatan Gupta } 201*6973a582SRatan Gupta else if (property.first == "LDAPType") 202*6973a582SRatan Gupta { 203*6973a582SRatan Gupta confData.serverType = *value; 204*6973a582SRatan Gupta } 205*6973a582SRatan Gupta else if (property.first == "GroupNameAttribute") 206*6973a582SRatan Gupta { 207*6973a582SRatan Gupta confData.groupAttribute = *value; 208*6973a582SRatan Gupta } 209*6973a582SRatan Gupta else if (property.first == "UserNameAttribute") 210*6973a582SRatan Gupta { 211*6973a582SRatan Gupta confData.userNameAttribute = *value; 212*6973a582SRatan Gupta } 213*6973a582SRatan Gupta } 214*6973a582SRatan Gupta } 215*6973a582SRatan Gupta } 216*6973a582SRatan Gupta 217*6973a582SRatan Gupta callback(true, confData); 218*6973a582SRatan Gupta break; 219*6973a582SRatan Gupta } 220*6973a582SRatan Gupta } 221*6973a582SRatan Gupta }; 222*6973a582SRatan Gupta auto getServiceName = [callback, getConfig(std::move(getConfig))]( 223*6973a582SRatan Gupta const boost::system::error_code ec, 224*6973a582SRatan Gupta const GetObjectType& resp) { 225*6973a582SRatan Gupta LDAPConfigData confData{}; 226*6973a582SRatan Gupta if (ec || resp.empty()) 227*6973a582SRatan Gupta { 228*6973a582SRatan Gupta BMCWEB_LOG_ERROR 229*6973a582SRatan Gupta << "DBUS response error during getting of service name: " << ec; 230*6973a582SRatan Gupta callback(false, confData); 231*6973a582SRatan Gupta return; 232*6973a582SRatan Gupta } 233*6973a582SRatan Gupta std::string service = resp.begin()->first; 234*6973a582SRatan Gupta crow::connections::systemBus->async_method_call( 235*6973a582SRatan Gupta std::move(getConfig), service, ldapRootObject, dbusObjManagerIntf, 236*6973a582SRatan Gupta "GetManagedObjects"); 237*6973a582SRatan Gupta }; 238*6973a582SRatan Gupta 239*6973a582SRatan Gupta const std::array<std::string, 2> interfaces = {ldapEnableInterface, 240*6973a582SRatan Gupta ldapConfigInterface}; 241*6973a582SRatan Gupta 242*6973a582SRatan Gupta crow::connections::systemBus->async_method_call( 243*6973a582SRatan Gupta std::move(getServiceName), mapperBusName, mapperObjectPath, mapperIntf, 244*6973a582SRatan Gupta "GetObject", ldapConfigObject, interfaces); 245*6973a582SRatan Gupta } 246*6973a582SRatan Gupta 2471abe55efSEd Tanous class AccountService : public Node 2481abe55efSEd Tanous { 24988d16c9aSLewanczyk, Dawid public: 2501abe55efSEd Tanous AccountService(CrowApp& app) : Node(app, "/redfish/v1/AccountService/") 2511abe55efSEd Tanous { 2523ebd75f7SEd Tanous entityPrivileges = { 2534b1b8683SBorawski.Lukasz {boost::beast::http::verb::get, 2544b1b8683SBorawski.Lukasz {{"ConfigureUsers"}, {"ConfigureManager"}}}, 255e0d918bcSEd Tanous {boost::beast::http::verb::head, {{"Login"}}}, 256e0d918bcSEd Tanous {boost::beast::http::verb::patch, {{"ConfigureUsers"}}}, 257e0d918bcSEd Tanous {boost::beast::http::verb::put, {{"ConfigureUsers"}}}, 258e0d918bcSEd Tanous {boost::beast::http::verb::delete_, {{"ConfigureUsers"}}}, 259e0d918bcSEd Tanous {boost::beast::http::verb::post, {{"ConfigureUsers"}}}}; 26088d16c9aSLewanczyk, Dawid } 26188d16c9aSLewanczyk, Dawid 26288d16c9aSLewanczyk, Dawid private: 26355c7b7a2SEd Tanous void doGet(crow::Response& res, const crow::Request& req, 2641abe55efSEd Tanous const std::vector<std::string>& params) override 2651abe55efSEd Tanous { 2663d958bbcSAppaRao Puli auto asyncResp = std::make_shared<AsyncResp>(res); 2673d958bbcSAppaRao Puli res.jsonValue = { 2683d958bbcSAppaRao Puli {"@odata.context", "/redfish/v1/" 2693d958bbcSAppaRao Puli "$metadata#AccountService.AccountService"}, 2703d958bbcSAppaRao Puli {"@odata.id", "/redfish/v1/AccountService"}, 2713d958bbcSAppaRao Puli {"@odata.type", "#AccountService." 272*6973a582SRatan Gupta "v1_3_1.AccountService"}, 2733d958bbcSAppaRao Puli {"Id", "AccountService"}, 2743d958bbcSAppaRao Puli {"Name", "Account Service"}, 2753d958bbcSAppaRao Puli {"Description", "Account Service"}, 2763d958bbcSAppaRao Puli {"ServiceEnabled", true}, 277343ff2e1SAppaRao Puli {"MaxPasswordLength", 20}, 2783d958bbcSAppaRao Puli {"Accounts", 2793d958bbcSAppaRao Puli {{"@odata.id", "/redfish/v1/AccountService/Accounts"}}}, 2803d958bbcSAppaRao Puli {"Roles", {{"@odata.id", "/redfish/v1/AccountService/Roles"}}}}; 2810f74e643SEd Tanous 2823d958bbcSAppaRao Puli crow::connections::systemBus->async_method_call( 2833d958bbcSAppaRao Puli [asyncResp]( 2843d958bbcSAppaRao Puli const boost::system::error_code ec, 2853d958bbcSAppaRao Puli const std::vector<std::pair< 286abf2add6SEd Tanous std::string, std::variant<uint32_t, uint16_t, uint8_t>>>& 2873d958bbcSAppaRao Puli propertiesList) { 2883d958bbcSAppaRao Puli if (ec) 2893d958bbcSAppaRao Puli { 2903d958bbcSAppaRao Puli messages::internalError(asyncResp->res); 2913d958bbcSAppaRao Puli return; 2923d958bbcSAppaRao Puli } 2933d958bbcSAppaRao Puli BMCWEB_LOG_DEBUG << "Got " << propertiesList.size() 2943d958bbcSAppaRao Puli << "properties for AccountService"; 2953d958bbcSAppaRao Puli for (const std::pair<std::string, 296abf2add6SEd Tanous std::variant<uint32_t, uint16_t, uint8_t>>& 2973d958bbcSAppaRao Puli property : propertiesList) 2983d958bbcSAppaRao Puli { 2993d958bbcSAppaRao Puli if (property.first == "MinPasswordLength") 3003d958bbcSAppaRao Puli { 3013d958bbcSAppaRao Puli const uint8_t* value = 302abf2add6SEd Tanous std::get_if<uint8_t>(&property.second); 3033d958bbcSAppaRao Puli if (value != nullptr) 3043d958bbcSAppaRao Puli { 3053d958bbcSAppaRao Puli asyncResp->res.jsonValue["MinPasswordLength"] = 3063d958bbcSAppaRao Puli *value; 3073d958bbcSAppaRao Puli } 3083d958bbcSAppaRao Puli } 3093d958bbcSAppaRao Puli if (property.first == "AccountUnlockTimeout") 3103d958bbcSAppaRao Puli { 3113d958bbcSAppaRao Puli const uint32_t* value = 312abf2add6SEd Tanous std::get_if<uint32_t>(&property.second); 3133d958bbcSAppaRao Puli if (value != nullptr) 3143d958bbcSAppaRao Puli { 3153d958bbcSAppaRao Puli asyncResp->res.jsonValue["AccountLockoutDuration"] = 3163d958bbcSAppaRao Puli *value; 3173d958bbcSAppaRao Puli } 3183d958bbcSAppaRao Puli } 3193d958bbcSAppaRao Puli if (property.first == "MaxLoginAttemptBeforeLockout") 3203d958bbcSAppaRao Puli { 3213d958bbcSAppaRao Puli const uint16_t* value = 322abf2add6SEd Tanous std::get_if<uint16_t>(&property.second); 3233d958bbcSAppaRao Puli if (value != nullptr) 3243d958bbcSAppaRao Puli { 3253d958bbcSAppaRao Puli asyncResp->res 3263d958bbcSAppaRao Puli .jsonValue["AccountLockoutThreshold"] = *value; 3273d958bbcSAppaRao Puli } 3283d958bbcSAppaRao Puli } 3293d958bbcSAppaRao Puli } 3303d958bbcSAppaRao Puli }, 3313d958bbcSAppaRao Puli "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user", 3323d958bbcSAppaRao Puli "org.freedesktop.DBus.Properties", "GetAll", 3333d958bbcSAppaRao Puli "xyz.openbmc_project.User.AccountPolicy"); 334*6973a582SRatan Gupta 335*6973a582SRatan Gupta std::string ldapType = "LDAP"; 336*6973a582SRatan Gupta getLDAPConfigData( 337*6973a582SRatan Gupta ldapType, 338*6973a582SRatan Gupta [asyncResp, ldapType](bool success, LDAPConfigData& confData) { 339*6973a582SRatan Gupta parseLDAPConfigData(asyncResp->res.jsonValue, confData); 340*6973a582SRatan Gupta }); 3413d958bbcSAppaRao Puli } 342*6973a582SRatan Gupta 3433d958bbcSAppaRao Puli void doPatch(crow::Response& res, const crow::Request& req, 3443d958bbcSAppaRao Puli const std::vector<std::string>& params) override 3453d958bbcSAppaRao Puli { 3463d958bbcSAppaRao Puli auto asyncResp = std::make_shared<AsyncResp>(res); 3473d958bbcSAppaRao Puli 3483d958bbcSAppaRao Puli std::optional<uint32_t> unlockTimeout; 3493d958bbcSAppaRao Puli std::optional<uint16_t> lockoutThreshold; 35019fb6e71SRatan Gupta std::optional<uint16_t> minPasswordLength; 35119fb6e71SRatan Gupta std::optional<uint16_t> maxPasswordLength; 35219fb6e71SRatan Gupta 3533d958bbcSAppaRao Puli if (!json_util::readJson(req, res, "AccountLockoutDuration", 3543d958bbcSAppaRao Puli unlockTimeout, "AccountLockoutThreshold", 35519fb6e71SRatan Gupta lockoutThreshold, "MaxPasswordLength", 35619fb6e71SRatan Gupta maxPasswordLength, "MinPasswordLength", 35719fb6e71SRatan Gupta minPasswordLength)) 3583d958bbcSAppaRao Puli { 3593d958bbcSAppaRao Puli return; 3603d958bbcSAppaRao Puli } 36119fb6e71SRatan Gupta 36219fb6e71SRatan Gupta if (minPasswordLength) 36319fb6e71SRatan Gupta { 36419fb6e71SRatan Gupta messages::propertyNotWritable(asyncResp->res, "MinPasswordLength"); 36519fb6e71SRatan Gupta } 36619fb6e71SRatan Gupta 36719fb6e71SRatan Gupta if (maxPasswordLength) 36819fb6e71SRatan Gupta { 36919fb6e71SRatan Gupta messages::propertyNotWritable(asyncResp->res, "MaxPasswordLength"); 37019fb6e71SRatan Gupta } 37119fb6e71SRatan Gupta 3723d958bbcSAppaRao Puli if (unlockTimeout) 3733d958bbcSAppaRao Puli { 3743d958bbcSAppaRao Puli crow::connections::systemBus->async_method_call( 3753d958bbcSAppaRao Puli [asyncResp](const boost::system::error_code ec) { 3763d958bbcSAppaRao Puli if (ec) 3773d958bbcSAppaRao Puli { 3783d958bbcSAppaRao Puli messages::internalError(asyncResp->res); 3793d958bbcSAppaRao Puli return; 3803d958bbcSAppaRao Puli } 381add6133bSRatan Gupta messages::success(asyncResp->res); 3823d958bbcSAppaRao Puli }, 3833d958bbcSAppaRao Puli "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user", 3843d958bbcSAppaRao Puli "org.freedesktop.DBus.Properties", "Set", 3853d958bbcSAppaRao Puli "xyz.openbmc_project.User.AccountPolicy", 386abf2add6SEd Tanous "AccountUnlockTimeout", std::variant<uint32_t>(*unlockTimeout)); 3873d958bbcSAppaRao Puli } 3883d958bbcSAppaRao Puli if (lockoutThreshold) 3893d958bbcSAppaRao Puli { 3903d958bbcSAppaRao Puli crow::connections::systemBus->async_method_call( 3913d958bbcSAppaRao Puli [asyncResp](const boost::system::error_code ec) { 3923d958bbcSAppaRao Puli if (ec) 3933d958bbcSAppaRao Puli { 3943d958bbcSAppaRao Puli messages::internalError(asyncResp->res); 3953d958bbcSAppaRao Puli return; 3963d958bbcSAppaRao Puli } 397add6133bSRatan Gupta messages::success(asyncResp->res); 3983d958bbcSAppaRao Puli }, 3993d958bbcSAppaRao Puli "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user", 4003d958bbcSAppaRao Puli "org.freedesktop.DBus.Properties", "Set", 4013d958bbcSAppaRao Puli "xyz.openbmc_project.User.AccountPolicy", 4023d958bbcSAppaRao Puli "MaxLoginAttemptBeforeLockout", 403abf2add6SEd Tanous std::variant<uint16_t>(*lockoutThreshold)); 4043d958bbcSAppaRao Puli } 40588d16c9aSLewanczyk, Dawid } 40688d16c9aSLewanczyk, Dawid }; 407f00032dbSTanous 408b9b2e0b2SEd Tanous class AccountsCollection : public Node 409b9b2e0b2SEd Tanous { 410b9b2e0b2SEd Tanous public: 411b9b2e0b2SEd Tanous AccountsCollection(CrowApp& app) : 412b9b2e0b2SEd Tanous Node(app, "/redfish/v1/AccountService/Accounts/") 413b9b2e0b2SEd Tanous { 414b9b2e0b2SEd Tanous entityPrivileges = { 415b9b2e0b2SEd Tanous {boost::beast::http::verb::get, 416b9b2e0b2SEd Tanous {{"ConfigureUsers"}, {"ConfigureManager"}}}, 417b9b2e0b2SEd Tanous {boost::beast::http::verb::head, {{"Login"}}}, 418b9b2e0b2SEd Tanous {boost::beast::http::verb::patch, {{"ConfigureUsers"}}}, 419b9b2e0b2SEd Tanous {boost::beast::http::verb::put, {{"ConfigureUsers"}}}, 420b9b2e0b2SEd Tanous {boost::beast::http::verb::delete_, {{"ConfigureUsers"}}}, 421b9b2e0b2SEd Tanous {boost::beast::http::verb::post, {{"ConfigureUsers"}}}}; 422b9b2e0b2SEd Tanous } 423b9b2e0b2SEd Tanous 424b9b2e0b2SEd Tanous private: 425b9b2e0b2SEd Tanous void doGet(crow::Response& res, const crow::Request& req, 426b9b2e0b2SEd Tanous const std::vector<std::string>& params) override 427b9b2e0b2SEd Tanous { 428b9b2e0b2SEd Tanous auto asyncResp = std::make_shared<AsyncResp>(res); 4290f74e643SEd Tanous res.jsonValue = {{"@odata.context", 4300f74e643SEd Tanous "/redfish/v1/" 4310f74e643SEd Tanous "$metadata#ManagerAccountCollection." 4320f74e643SEd Tanous "ManagerAccountCollection"}, 4330f74e643SEd Tanous {"@odata.id", "/redfish/v1/AccountService/Accounts"}, 4340f74e643SEd Tanous {"@odata.type", "#ManagerAccountCollection." 4350f74e643SEd Tanous "ManagerAccountCollection"}, 4360f74e643SEd Tanous {"Name", "Accounts Collection"}, 4370f74e643SEd Tanous {"Description", "BMC User Accounts"}}; 4380f74e643SEd Tanous 439b9b2e0b2SEd Tanous crow::connections::systemBus->async_method_call( 440b9b2e0b2SEd Tanous [asyncResp](const boost::system::error_code ec, 441b9b2e0b2SEd Tanous const ManagedObjectType& users) { 442b9b2e0b2SEd Tanous if (ec) 443b9b2e0b2SEd Tanous { 444f12894f8SJason M. Bills messages::internalError(asyncResp->res); 445b9b2e0b2SEd Tanous return; 446b9b2e0b2SEd Tanous } 447b9b2e0b2SEd Tanous 448b9b2e0b2SEd Tanous nlohmann::json& memberArray = 449b9b2e0b2SEd Tanous asyncResp->res.jsonValue["Members"]; 450b9b2e0b2SEd Tanous memberArray = nlohmann::json::array(); 451b9b2e0b2SEd Tanous 452b9b2e0b2SEd Tanous asyncResp->res.jsonValue["Members@odata.count"] = users.size(); 453b9b2e0b2SEd Tanous for (auto& user : users) 454b9b2e0b2SEd Tanous { 455b9b2e0b2SEd Tanous const std::string& path = 456b9b2e0b2SEd Tanous static_cast<const std::string&>(user.first); 457b9b2e0b2SEd Tanous std::size_t lastIndex = path.rfind("/"); 458b9b2e0b2SEd Tanous if (lastIndex == std::string::npos) 459b9b2e0b2SEd Tanous { 460b9b2e0b2SEd Tanous lastIndex = 0; 461b9b2e0b2SEd Tanous } 462b9b2e0b2SEd Tanous else 463b9b2e0b2SEd Tanous { 464b9b2e0b2SEd Tanous lastIndex += 1; 465b9b2e0b2SEd Tanous } 466b9b2e0b2SEd Tanous memberArray.push_back( 467b9b2e0b2SEd Tanous {{"@odata.id", "/redfish/v1/AccountService/Accounts/" + 468b9b2e0b2SEd Tanous path.substr(lastIndex)}}); 469b9b2e0b2SEd Tanous } 470b9b2e0b2SEd Tanous }, 471b9b2e0b2SEd Tanous "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user", 472b9b2e0b2SEd Tanous "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 473b9b2e0b2SEd Tanous } 47404ae99ecSEd Tanous void doPost(crow::Response& res, const crow::Request& req, 47504ae99ecSEd Tanous const std::vector<std::string>& params) override 47604ae99ecSEd Tanous { 47704ae99ecSEd Tanous auto asyncResp = std::make_shared<AsyncResp>(res); 47804ae99ecSEd Tanous 4799712f8acSEd Tanous std::string username; 4809712f8acSEd Tanous std::string password; 481a24526dcSEd Tanous std::optional<std::string> roleId("User"); 482a24526dcSEd Tanous std::optional<bool> enabled = true; 4839712f8acSEd Tanous if (!json_util::readJson(req, res, "UserName", username, "Password", 4849712f8acSEd Tanous password, "RoleId", roleId, "Enabled", 4859712f8acSEd Tanous enabled)) 48604ae99ecSEd Tanous { 48704ae99ecSEd Tanous return; 48804ae99ecSEd Tanous } 48904ae99ecSEd Tanous 49084e12cb7SAppaRao Puli std::string priv = getRoleIdFromPrivilege(*roleId); 49184e12cb7SAppaRao Puli if (priv.empty()) 49204ae99ecSEd Tanous { 493f12894f8SJason M. Bills messages::propertyValueNotInList(asyncResp->res, *roleId, "RoleId"); 49404ae99ecSEd Tanous return; 49504ae99ecSEd Tanous } 4969712f8acSEd Tanous roleId = priv; 49704ae99ecSEd Tanous 49804ae99ecSEd Tanous crow::connections::systemBus->async_method_call( 4999712f8acSEd Tanous [asyncResp, username, password{std::move(password)}]( 50004ae99ecSEd Tanous const boost::system::error_code ec) { 50104ae99ecSEd Tanous if (ec) 50204ae99ecSEd Tanous { 50304ae99ecSEd Tanous messages::resourceAlreadyExists( 504f12894f8SJason M. Bills asyncResp->res, "#ManagerAccount.v1_0_3.ManagerAccount", 505f12894f8SJason M. Bills "UserName", username); 50604ae99ecSEd Tanous return; 50704ae99ecSEd Tanous } 50804ae99ecSEd Tanous 50904ae99ecSEd Tanous if (!pamUpdatePassword(username, password)) 51004ae99ecSEd Tanous { 51104ae99ecSEd Tanous // At this point we have a user that's been created, but the 51204ae99ecSEd Tanous // password set failed. Something is wrong, so delete the 51304ae99ecSEd Tanous // user that we've already created 51404ae99ecSEd Tanous crow::connections::systemBus->async_method_call( 51504ae99ecSEd Tanous [asyncResp](const boost::system::error_code ec) { 51604ae99ecSEd Tanous if (ec) 51704ae99ecSEd Tanous { 518f12894f8SJason M. Bills messages::internalError(asyncResp->res); 51904ae99ecSEd Tanous return; 52004ae99ecSEd Tanous } 52104ae99ecSEd Tanous 522f12894f8SJason M. Bills messages::invalidObject(asyncResp->res, "Password"); 52304ae99ecSEd Tanous }, 52404ae99ecSEd Tanous "xyz.openbmc_project.User.Manager", 52504ae99ecSEd Tanous "/xyz/openbmc_project/user/" + username, 52604ae99ecSEd Tanous "xyz.openbmc_project.Object.Delete", "Delete"); 52704ae99ecSEd Tanous 52804ae99ecSEd Tanous BMCWEB_LOG_ERROR << "pamUpdatePassword Failed"; 52904ae99ecSEd Tanous return; 53004ae99ecSEd Tanous } 53104ae99ecSEd Tanous 532f12894f8SJason M. Bills messages::created(asyncResp->res); 53304ae99ecSEd Tanous asyncResp->res.addHeader( 53404ae99ecSEd Tanous "Location", 53504ae99ecSEd Tanous "/redfish/v1/AccountService/Accounts/" + username); 53604ae99ecSEd Tanous }, 53704ae99ecSEd Tanous "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user", 5389712f8acSEd Tanous "xyz.openbmc_project.User.Manager", "CreateUser", username, 53904ae99ecSEd Tanous std::array<const char*, 4>{"ipmi", "redfish", "ssh", "web"}, 5409712f8acSEd Tanous *roleId, *enabled); 54104ae99ecSEd Tanous } 542b9b2e0b2SEd Tanous }; 543b9b2e0b2SEd Tanous 544a840879dSEd Tanous template <typename Callback> 545a840879dSEd Tanous inline void checkDbusPathExists(const std::string& path, Callback&& callback) 546a840879dSEd Tanous { 547a840879dSEd Tanous using GetObjectType = 548a840879dSEd Tanous std::vector<std::pair<std::string, std::vector<std::string>>>; 549a840879dSEd Tanous 550a840879dSEd Tanous crow::connections::systemBus->async_method_call( 551a840879dSEd Tanous [callback{std::move(callback)}](const boost::system::error_code ec, 552a840879dSEd Tanous const GetObjectType& object_names) { 55384e12cb7SAppaRao Puli callback(!ec && object_names.size() != 0); 554a840879dSEd Tanous }, 555a840879dSEd Tanous "xyz.openbmc_project.ObjectMapper", 556a840879dSEd Tanous "/xyz/openbmc_project/object_mapper", 557a840879dSEd Tanous "xyz.openbmc_project.ObjectMapper", "GetObject", path, 558a840879dSEd Tanous std::array<std::string, 0>()); 559a840879dSEd Tanous } 560a840879dSEd Tanous 561b9b2e0b2SEd Tanous class ManagerAccount : public Node 562b9b2e0b2SEd Tanous { 563b9b2e0b2SEd Tanous public: 564b9b2e0b2SEd Tanous ManagerAccount(CrowApp& app) : 565b9b2e0b2SEd Tanous Node(app, "/redfish/v1/AccountService/Accounts/<str>/", std::string()) 566b9b2e0b2SEd Tanous { 567b9b2e0b2SEd Tanous entityPrivileges = { 568b9b2e0b2SEd Tanous {boost::beast::http::verb::get, 569b9b2e0b2SEd Tanous {{"ConfigureUsers"}, {"ConfigureManager"}, {"ConfigureSelf"}}}, 570b9b2e0b2SEd Tanous {boost::beast::http::verb::head, {{"Login"}}}, 571b9b2e0b2SEd Tanous {boost::beast::http::verb::patch, {{"ConfigureUsers"}}}, 572b9b2e0b2SEd Tanous {boost::beast::http::verb::put, {{"ConfigureUsers"}}}, 573b9b2e0b2SEd Tanous {boost::beast::http::verb::delete_, {{"ConfigureUsers"}}}, 574b9b2e0b2SEd Tanous {boost::beast::http::verb::post, {{"ConfigureUsers"}}}}; 575b9b2e0b2SEd Tanous } 576b9b2e0b2SEd Tanous 577b9b2e0b2SEd Tanous private: 578b9b2e0b2SEd Tanous void doGet(crow::Response& res, const crow::Request& req, 579b9b2e0b2SEd Tanous const std::vector<std::string>& params) override 580b9b2e0b2SEd Tanous { 5810f74e643SEd Tanous res.jsonValue = { 5820f74e643SEd Tanous {"@odata.context", 5830f74e643SEd Tanous "/redfish/v1/$metadata#ManagerAccount.ManagerAccount"}, 5840f74e643SEd Tanous {"@odata.type", "#ManagerAccount.v1_0_3.ManagerAccount"}, 5850f74e643SEd Tanous {"Name", "User Account"}, 5860f74e643SEd Tanous {"Description", "User Account"}, 5870f74e643SEd Tanous {"Password", nullptr}, 58884e12cb7SAppaRao Puli {"RoleId", "Administrator"}}; 5890f74e643SEd Tanous 590b9b2e0b2SEd Tanous auto asyncResp = std::make_shared<AsyncResp>(res); 591b9b2e0b2SEd Tanous 592b9b2e0b2SEd Tanous if (params.size() != 1) 593b9b2e0b2SEd Tanous { 594f12894f8SJason M. Bills messages::internalError(asyncResp->res); 595b9b2e0b2SEd Tanous return; 596b9b2e0b2SEd Tanous } 597b9b2e0b2SEd Tanous 598b9b2e0b2SEd Tanous crow::connections::systemBus->async_method_call( 599b9b2e0b2SEd Tanous [asyncResp, accountName{std::string(params[0])}]( 600b9b2e0b2SEd Tanous const boost::system::error_code ec, 601b9b2e0b2SEd Tanous const ManagedObjectType& users) { 602b9b2e0b2SEd Tanous if (ec) 603b9b2e0b2SEd Tanous { 604f12894f8SJason M. Bills messages::internalError(asyncResp->res); 605b9b2e0b2SEd Tanous return; 606b9b2e0b2SEd Tanous } 60784e12cb7SAppaRao Puli auto userIt = users.begin(); 608b9b2e0b2SEd Tanous 60984e12cb7SAppaRao Puli for (; userIt != users.end(); userIt++) 610b9b2e0b2SEd Tanous { 61184e12cb7SAppaRao Puli if (boost::ends_with(userIt->first.str, "/" + accountName)) 612b9b2e0b2SEd Tanous { 61384e12cb7SAppaRao Puli break; 614b9b2e0b2SEd Tanous } 615b9b2e0b2SEd Tanous } 61684e12cb7SAppaRao Puli if (userIt == users.end()) 617b9b2e0b2SEd Tanous { 61884e12cb7SAppaRao Puli messages::resourceNotFound(asyncResp->res, "ManagerAccount", 61984e12cb7SAppaRao Puli accountName); 62084e12cb7SAppaRao Puli return; 62184e12cb7SAppaRao Puli } 62284e12cb7SAppaRao Puli for (const auto& interface : userIt->second) 62365b0dc32SEd Tanous { 62465b0dc32SEd Tanous if (interface.first == 62565b0dc32SEd Tanous "xyz.openbmc_project.User.Attributes") 62665b0dc32SEd Tanous { 62765b0dc32SEd Tanous for (const auto& property : interface.second) 62865b0dc32SEd Tanous { 62965b0dc32SEd Tanous if (property.first == "UserEnabled") 63065b0dc32SEd Tanous { 63165b0dc32SEd Tanous const bool* userEnabled = 632abf2add6SEd Tanous std::get_if<bool>(&property.second); 63365b0dc32SEd Tanous if (userEnabled == nullptr) 63465b0dc32SEd Tanous { 63565b0dc32SEd Tanous BMCWEB_LOG_ERROR 63665b0dc32SEd Tanous << "UserEnabled wasn't a bool"; 63784e12cb7SAppaRao Puli messages::internalError(asyncResp->res); 63884e12cb7SAppaRao Puli return; 63965b0dc32SEd Tanous } 64065b0dc32SEd Tanous asyncResp->res.jsonValue["Enabled"] = 64165b0dc32SEd Tanous *userEnabled; 64265b0dc32SEd Tanous } 64365b0dc32SEd Tanous else if (property.first == 64465b0dc32SEd Tanous "UserLockedForFailedAttempt") 64565b0dc32SEd Tanous { 64665b0dc32SEd Tanous const bool* userLocked = 647abf2add6SEd Tanous std::get_if<bool>(&property.second); 64865b0dc32SEd Tanous if (userLocked == nullptr) 64965b0dc32SEd Tanous { 65084e12cb7SAppaRao Puli BMCWEB_LOG_ERROR << "UserLockedForF" 65184e12cb7SAppaRao Puli "ailedAttempt " 65284e12cb7SAppaRao Puli "wasn't a bool"; 65384e12cb7SAppaRao Puli messages::internalError(asyncResp->res); 65484e12cb7SAppaRao Puli return; 65565b0dc32SEd Tanous } 65665b0dc32SEd Tanous asyncResp->res.jsonValue["Locked"] = 65765b0dc32SEd Tanous *userLocked; 65824c8542dSRatan Gupta asyncResp->res.jsonValue 65924c8542dSRatan Gupta ["Locked@Redfish.AllowableValues"] = { 6604d64ce34SGunnar Mills "false"}; 66165b0dc32SEd Tanous } 66284e12cb7SAppaRao Puli else if (property.first == "UserPrivilege") 66384e12cb7SAppaRao Puli { 66484e12cb7SAppaRao Puli const std::string* userRolePtr = 665abf2add6SEd Tanous std::get_if<std::string>(&property.second); 66684e12cb7SAppaRao Puli if (userRolePtr == nullptr) 66784e12cb7SAppaRao Puli { 66884e12cb7SAppaRao Puli BMCWEB_LOG_ERROR 66984e12cb7SAppaRao Puli << "UserPrivilege wasn't a " 67084e12cb7SAppaRao Puli "string"; 67184e12cb7SAppaRao Puli messages::internalError(asyncResp->res); 67284e12cb7SAppaRao Puli return; 67384e12cb7SAppaRao Puli } 67484e12cb7SAppaRao Puli std::string priv = 67584e12cb7SAppaRao Puli getPrivilegeFromRoleId(*userRolePtr); 67684e12cb7SAppaRao Puli if (priv.empty()) 67784e12cb7SAppaRao Puli { 67884e12cb7SAppaRao Puli BMCWEB_LOG_ERROR << "Invalid user role"; 67984e12cb7SAppaRao Puli messages::internalError(asyncResp->res); 68084e12cb7SAppaRao Puli return; 68184e12cb7SAppaRao Puli } 68284e12cb7SAppaRao Puli asyncResp->res.jsonValue["RoleId"] = priv; 68384e12cb7SAppaRao Puli 68484e12cb7SAppaRao Puli asyncResp->res.jsonValue["Links"]["Role"] = { 68584e12cb7SAppaRao Puli {"@odata.id", "/redfish/v1/AccountService/" 68684e12cb7SAppaRao Puli "Roles/" + 68784e12cb7SAppaRao Puli priv}}; 68884e12cb7SAppaRao Puli } 68965b0dc32SEd Tanous } 69065b0dc32SEd Tanous } 69165b0dc32SEd Tanous } 69265b0dc32SEd Tanous 693b9b2e0b2SEd Tanous asyncResp->res.jsonValue["@odata.id"] = 69484e12cb7SAppaRao Puli "/redfish/v1/AccountService/Accounts/" + accountName; 695b9b2e0b2SEd Tanous asyncResp->res.jsonValue["Id"] = accountName; 696b9b2e0b2SEd Tanous asyncResp->res.jsonValue["UserName"] = accountName; 697b9b2e0b2SEd Tanous }, 698b9b2e0b2SEd Tanous "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user", 699b9b2e0b2SEd Tanous "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 700b9b2e0b2SEd Tanous } 701a840879dSEd Tanous 702a840879dSEd Tanous void doPatch(crow::Response& res, const crow::Request& req, 703a840879dSEd Tanous const std::vector<std::string>& params) override 704a840879dSEd Tanous { 705a840879dSEd Tanous auto asyncResp = std::make_shared<AsyncResp>(res); 706a840879dSEd Tanous if (params.size() != 1) 707a840879dSEd Tanous { 708f12894f8SJason M. Bills messages::internalError(asyncResp->res); 709a840879dSEd Tanous return; 710a840879dSEd Tanous } 711a840879dSEd Tanous 712a24526dcSEd Tanous std::optional<std::string> newUserName; 713a24526dcSEd Tanous std::optional<std::string> password; 714a24526dcSEd Tanous std::optional<bool> enabled; 715a24526dcSEd Tanous std::optional<std::string> roleId; 71624c8542dSRatan Gupta std::optional<bool> locked; 71784e12cb7SAppaRao Puli if (!json_util::readJson(req, res, "UserName", newUserName, "Password", 71824c8542dSRatan Gupta password, "RoleId", roleId, "Enabled", enabled, 71924c8542dSRatan Gupta "Locked", locked)) 720a840879dSEd Tanous { 721a840879dSEd Tanous return; 722a840879dSEd Tanous } 723a840879dSEd Tanous 72484e12cb7SAppaRao Puli const std::string& username = params[0]; 72584e12cb7SAppaRao Puli 72684e12cb7SAppaRao Puli if (!newUserName) 727a840879dSEd Tanous { 72884e12cb7SAppaRao Puli // If the username isn't being updated, we can update the properties 72984e12cb7SAppaRao Puli // directly 73024c8542dSRatan Gupta updateUserProperties(asyncResp, username, password, enabled, roleId, 73124c8542dSRatan Gupta locked); 73284e12cb7SAppaRao Puli return; 73384e12cb7SAppaRao Puli } 73484e12cb7SAppaRao Puli else 73584e12cb7SAppaRao Puli { 73684e12cb7SAppaRao Puli crow::connections::systemBus->async_method_call( 73784e12cb7SAppaRao Puli [this, asyncResp, username, password(std::move(password)), 73884e12cb7SAppaRao Puli roleId(std::move(roleId)), enabled(std::move(enabled)), 73924c8542dSRatan Gupta newUser{std::string(*newUserName)}, locked(std::move(locked))]( 74084e12cb7SAppaRao Puli const boost::system::error_code ec) { 74184e12cb7SAppaRao Puli if (ec) 74284e12cb7SAppaRao Puli { 74384e12cb7SAppaRao Puli BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec; 744a840879dSEd Tanous messages::resourceNotFound( 74584e12cb7SAppaRao Puli asyncResp->res, 74684e12cb7SAppaRao Puli "#ManagerAccount.v1_0_3.ManagerAccount", username); 747a840879dSEd Tanous return; 748a840879dSEd Tanous } 749a840879dSEd Tanous 75084e12cb7SAppaRao Puli updateUserProperties(asyncResp, newUser, password, enabled, 75124c8542dSRatan Gupta roleId, locked); 75284e12cb7SAppaRao Puli }, 75384e12cb7SAppaRao Puli "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user", 75484e12cb7SAppaRao Puli "xyz.openbmc_project.User.Manager", "RenameUser", username, 75584e12cb7SAppaRao Puli *newUserName); 75684e12cb7SAppaRao Puli } 75784e12cb7SAppaRao Puli } 75884e12cb7SAppaRao Puli 75984e12cb7SAppaRao Puli void updateUserProperties(std::shared_ptr<AsyncResp> asyncResp, 76084e12cb7SAppaRao Puli const std::string& username, 761a24526dcSEd Tanous std::optional<std::string> password, 762a24526dcSEd Tanous std::optional<bool> enabled, 76324c8542dSRatan Gupta std::optional<std::string> roleId, 76424c8542dSRatan Gupta std::optional<bool> locked) 76584e12cb7SAppaRao Puli { 7669712f8acSEd Tanous if (password) 767a840879dSEd Tanous { 7689712f8acSEd Tanous if (!pamUpdatePassword(username, *password)) 769a840879dSEd Tanous { 770a840879dSEd Tanous BMCWEB_LOG_ERROR << "pamUpdatePassword Failed"; 771f12894f8SJason M. Bills messages::internalError(asyncResp->res); 772a840879dSEd Tanous return; 773a840879dSEd Tanous } 774a840879dSEd Tanous } 775a840879dSEd Tanous 77624c8542dSRatan Gupta std::string dbusObjectPath = "/xyz/openbmc_project/user/" + username; 77724c8542dSRatan Gupta dbus::utility::escapePathForDbus(dbusObjectPath); 77824c8542dSRatan Gupta 77924c8542dSRatan Gupta checkDbusPathExists( 78024c8542dSRatan Gupta dbusObjectPath, 78124c8542dSRatan Gupta [dbusObjectPath(std::move(dbusObjectPath)), username, 78224c8542dSRatan Gupta password(std::move(password)), roleId(std::move(roleId)), 78324c8542dSRatan Gupta enabled(std::move(enabled)), locked(std::move(locked)), 78424c8542dSRatan Gupta asyncResp{std::move(asyncResp)}](int rc) { 78524c8542dSRatan Gupta if (!rc) 78624c8542dSRatan Gupta { 78724c8542dSRatan Gupta messages::invalidObject(asyncResp->res, username.c_str()); 78824c8542dSRatan Gupta return; 78924c8542dSRatan Gupta } 7909712f8acSEd Tanous if (enabled) 791a840879dSEd Tanous { 792a840879dSEd Tanous crow::connections::systemBus->async_method_call( 793a840879dSEd Tanous [asyncResp](const boost::system::error_code ec) { 794a840879dSEd Tanous if (ec) 795a840879dSEd Tanous { 79624c8542dSRatan Gupta BMCWEB_LOG_ERROR << "D-Bus responses error: " 79724c8542dSRatan Gupta << ec; 798f12894f8SJason M. Bills messages::internalError(asyncResp->res); 799a840879dSEd Tanous return; 800a840879dSEd Tanous } 80184e12cb7SAppaRao Puli messages::success(asyncResp->res); 80284e12cb7SAppaRao Puli return; 80384e12cb7SAppaRao Puli }, 80484e12cb7SAppaRao Puli "xyz.openbmc_project.User.Manager", 80524c8542dSRatan Gupta dbusObjectPath.c_str(), 80684e12cb7SAppaRao Puli "org.freedesktop.DBus.Properties", "Set", 80784e12cb7SAppaRao Puli "xyz.openbmc_project.User.Attributes", "UserEnabled", 808abf2add6SEd Tanous std::variant<bool>{*enabled}); 80984e12cb7SAppaRao Puli } 81084e12cb7SAppaRao Puli 81184e12cb7SAppaRao Puli if (roleId) 81284e12cb7SAppaRao Puli { 81384e12cb7SAppaRao Puli std::string priv = getRoleIdFromPrivilege(*roleId); 81484e12cb7SAppaRao Puli if (priv.empty()) 81584e12cb7SAppaRao Puli { 81624c8542dSRatan Gupta messages::propertyValueNotInList(asyncResp->res, 81724c8542dSRatan Gupta *roleId, "RoleId"); 81884e12cb7SAppaRao Puli return; 81984e12cb7SAppaRao Puli } 82084e12cb7SAppaRao Puli 82184e12cb7SAppaRao Puli crow::connections::systemBus->async_method_call( 82284e12cb7SAppaRao Puli [asyncResp](const boost::system::error_code ec) { 82384e12cb7SAppaRao Puli if (ec) 82484e12cb7SAppaRao Puli { 82524c8542dSRatan Gupta BMCWEB_LOG_ERROR << "D-Bus responses error: " 82624c8542dSRatan Gupta << ec; 82784e12cb7SAppaRao Puli messages::internalError(asyncResp->res); 82884e12cb7SAppaRao Puli return; 82984e12cb7SAppaRao Puli } 830f12894f8SJason M. Bills messages::success(asyncResp->res); 831a840879dSEd Tanous }, 832a840879dSEd Tanous "xyz.openbmc_project.User.Manager", 83324c8542dSRatan Gupta dbusObjectPath.c_str(), 834a840879dSEd Tanous "org.freedesktop.DBus.Properties", "Set", 83584e12cb7SAppaRao Puli "xyz.openbmc_project.User.Attributes", "UserPrivilege", 836abf2add6SEd Tanous std::variant<std::string>{priv}); 837a840879dSEd Tanous } 83824c8542dSRatan Gupta 83924c8542dSRatan Gupta if (locked) 84024c8542dSRatan Gupta { 84124c8542dSRatan Gupta // admin can unlock the account which is locked by 84224c8542dSRatan Gupta // successive authentication failures but admin should not 84324c8542dSRatan Gupta // be allowed to lock an account. 84424c8542dSRatan Gupta if (*locked) 84524c8542dSRatan Gupta { 84624c8542dSRatan Gupta messages::propertyValueNotInList(asyncResp->res, "true", 84724c8542dSRatan Gupta "Locked"); 84824c8542dSRatan Gupta return; 84924c8542dSRatan Gupta } 85024c8542dSRatan Gupta 85124c8542dSRatan Gupta crow::connections::systemBus->async_method_call( 85224c8542dSRatan Gupta [asyncResp](const boost::system::error_code ec) { 85324c8542dSRatan Gupta if (ec) 85424c8542dSRatan Gupta { 85524c8542dSRatan Gupta BMCWEB_LOG_ERROR << "D-Bus responses error: " 85624c8542dSRatan Gupta << ec; 85724c8542dSRatan Gupta messages::internalError(asyncResp->res); 85824c8542dSRatan Gupta return; 85924c8542dSRatan Gupta } 86024c8542dSRatan Gupta messages::success(asyncResp->res); 86124c8542dSRatan Gupta return; 86224c8542dSRatan Gupta }, 86324c8542dSRatan Gupta "xyz.openbmc_project.User.Manager", 86424c8542dSRatan Gupta dbusObjectPath.c_str(), 86524c8542dSRatan Gupta "org.freedesktop.DBus.Properties", "Set", 86624c8542dSRatan Gupta "xyz.openbmc_project.User.Attributes", 86724c8542dSRatan Gupta "UserLockedForFailedAttempt", 86824c8542dSRatan Gupta sdbusplus::message::variant<bool>{*locked}); 86924c8542dSRatan Gupta } 87024c8542dSRatan Gupta }); 871a840879dSEd Tanous } 87206e086d9SEd Tanous 87306e086d9SEd Tanous void doDelete(crow::Response& res, const crow::Request& req, 87406e086d9SEd Tanous const std::vector<std::string>& params) override 87506e086d9SEd Tanous { 87606e086d9SEd Tanous auto asyncResp = std::make_shared<AsyncResp>(res); 87706e086d9SEd Tanous 87806e086d9SEd Tanous if (params.size() != 1) 87906e086d9SEd Tanous { 880f12894f8SJason M. Bills messages::internalError(asyncResp->res); 88106e086d9SEd Tanous return; 88206e086d9SEd Tanous } 88306e086d9SEd Tanous 88406e086d9SEd Tanous const std::string userPath = "/xyz/openbmc_project/user/" + params[0]; 88506e086d9SEd Tanous 88606e086d9SEd Tanous crow::connections::systemBus->async_method_call( 88706e086d9SEd Tanous [asyncResp, username{std::move(params[0])}]( 88806e086d9SEd Tanous const boost::system::error_code ec) { 88906e086d9SEd Tanous if (ec) 89006e086d9SEd Tanous { 89106e086d9SEd Tanous messages::resourceNotFound( 892f12894f8SJason M. Bills asyncResp->res, "#ManagerAccount.v1_0_3.ManagerAccount", 893f12894f8SJason M. Bills username); 89406e086d9SEd Tanous return; 89506e086d9SEd Tanous } 89606e086d9SEd Tanous 897f12894f8SJason M. Bills messages::accountRemoved(asyncResp->res); 89806e086d9SEd Tanous }, 89906e086d9SEd Tanous "xyz.openbmc_project.User.Manager", userPath, 90006e086d9SEd Tanous "xyz.openbmc_project.Object.Delete", "Delete"); 90106e086d9SEd Tanous } 90284e12cb7SAppaRao Puli }; 90388d16c9aSLewanczyk, Dawid 90488d16c9aSLewanczyk, Dawid } // namespace redfish 905