Move AccountService to separate methods
Similar to the transforms we've done elsewhere, move AccountService to
use non-lambda methods.
Tested:
Redfish service validator passes.
Signed-off-by: Ed Tanous <edtanous@google.com>
Change-Id: I1bf6d104b48552444e75f3e443822c16a45bb813
diff --git a/redfish-core/lib/account_service.hpp b/redfish-core/lib/account_service.hpp
index 553d41e..a773048 100644
--- a/redfish-core/lib/account_service.hpp
+++ b/redfish-core/lib/account_service.hpp
@@ -1238,606 +1238,712 @@
});
}
+inline void
+ handleAccountServiceGet(App& app, const crow::Request& req,
+ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
+{
+ if (!redfish::setUpRedfishRoute(app, req, asyncResp))
+ {
+ return;
+ }
+ const persistent_data::AuthConfigMethods& authMethodsConfig =
+ persistent_data::SessionStore::getInstance().getAuthMethodsConfig();
+
+ nlohmann::json& json = asyncResp->res.jsonValue;
+ json["@odata.id"] = "/redfish/v1/AccountService";
+ json["@odata.type"] = "#AccountService."
+ "v1_10_0.AccountService";
+ json["Id"] = "AccountService";
+ json["Name"] = "Account Service";
+ json["Description"] = "Account Service";
+ json["ServiceEnabled"] = true;
+ json["MaxPasswordLength"] = 20;
+ json["Accounts"]["@odata.id"] = "/redfish/v1/AccountService/Accounts";
+ json["Roles"]["@odata.id"] = "/redfish/v1/AccountService/Roles";
+ json["Oem"]["OpenBMC"]["@odata.type"] =
+ "#OemAccountService.v1_0_0.AccountService";
+ json["Oem"]["OpenBMC"]["@odata.id"] =
+ "/redfish/v1/AccountService#/Oem/OpenBMC";
+ json["Oem"]["OpenBMC"]["AuthMethods"]["BasicAuth"] =
+ authMethodsConfig.basic;
+ json["Oem"]["OpenBMC"]["AuthMethods"]["SessionToken"] =
+ authMethodsConfig.sessionToken;
+ json["Oem"]["OpenBMC"]["AuthMethods"]["XToken"] = authMethodsConfig.xtoken;
+ json["Oem"]["OpenBMC"]["AuthMethods"]["Cookie"] = authMethodsConfig.cookie;
+ json["Oem"]["OpenBMC"]["AuthMethods"]["TLS"] = authMethodsConfig.tls;
+
+ // /redfish/v1/AccountService/LDAP/Certificates is something only
+ // ConfigureManager can access then only display when the user has
+ // permissions ConfigureManager
+ Privileges effectiveUserPrivileges =
+ redfish::getUserPrivileges(req.userRole);
+
+ if (isOperationAllowedWithPrivileges({{"ConfigureManager"}},
+ effectiveUserPrivileges))
+ {
+ asyncResp->res.jsonValue["LDAP"]["Certificates"]["@odata.id"] =
+ "/redfish/v1/AccountService/LDAP/Certificates";
+ }
+ crow::connections::systemBus->async_method_call(
+ [asyncResp](const boost::system::error_code ec,
+ const dbus::utility::DBusPropertiesMap& propertiesList) {
+ if (ec)
+ {
+ messages::internalError(asyncResp->res);
+ return;
+ }
+ BMCWEB_LOG_DEBUG << "Got " << propertiesList.size()
+ << "properties for AccountService";
+ for (const std::pair<std::string, dbus::utility::DbusVariantType>&
+ property : propertiesList)
+ {
+ if (property.first == "MinPasswordLength")
+ {
+ const uint8_t* value = std::get_if<uint8_t>(&property.second);
+ if (value != nullptr)
+ {
+ asyncResp->res.jsonValue["MinPasswordLength"] = *value;
+ }
+ }
+ if (property.first == "AccountUnlockTimeout")
+ {
+ const uint32_t* value = std::get_if<uint32_t>(&property.second);
+ if (value != nullptr)
+ {
+ asyncResp->res.jsonValue["AccountLockoutDuration"] = *value;
+ }
+ }
+ if (property.first == "MaxLoginAttemptBeforeLockout")
+ {
+ const uint16_t* value = std::get_if<uint16_t>(&property.second);
+ if (value != nullptr)
+ {
+ asyncResp->res.jsonValue["AccountLockoutThreshold"] =
+ *value;
+ }
+ }
+ }
+ },
+ "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
+ "org.freedesktop.DBus.Properties", "GetAll",
+ "xyz.openbmc_project.User.AccountPolicy");
+
+ auto callback = [asyncResp](bool success, LDAPConfigData& confData,
+ const std::string& ldapType) {
+ if (!success)
+ {
+ return;
+ }
+ parseLDAPConfigData(asyncResp->res.jsonValue, confData, ldapType);
+ };
+
+ getLDAPConfigData("LDAP", callback);
+ getLDAPConfigData("ActiveDirectory", callback);
+}
+
+inline void handleAccountServicePatch(
+ App& app, const crow::Request& req,
+ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
+{
+ if (!redfish::setUpRedfishRoute(app, req, asyncResp))
+ {
+ return;
+ }
+ std::optional<uint32_t> unlockTimeout;
+ std::optional<uint16_t> lockoutThreshold;
+ std::optional<uint8_t> minPasswordLength;
+ std::optional<uint16_t> maxPasswordLength;
+ std::optional<nlohmann::json> ldapObject;
+ std::optional<nlohmann::json> activeDirectoryObject;
+ std::optional<nlohmann::json> oemObject;
+
+ if (!json_util::readJsonPatch(
+ req, asyncResp->res, "AccountLockoutDuration", unlockTimeout,
+ "AccountLockoutThreshold", lockoutThreshold, "MaxPasswordLength",
+ maxPasswordLength, "MinPasswordLength", minPasswordLength, "LDAP",
+ ldapObject, "ActiveDirectory", activeDirectoryObject, "Oem",
+ oemObject))
+ {
+ return;
+ }
+
+ if (minPasswordLength)
+ {
+ crow::connections::systemBus->async_method_call(
+ [asyncResp](const boost::system::error_code ec) {
+ if (ec)
+ {
+ messages::internalError(asyncResp->res);
+ return;
+ }
+ messages::success(asyncResp->res);
+ },
+ "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
+ "org.freedesktop.DBus.Properties", "Set",
+ "xyz.openbmc_project.User.AccountPolicy", "MinPasswordLength",
+ dbus::utility::DbusVariantType(*minPasswordLength));
+ }
+
+ if (maxPasswordLength)
+ {
+ messages::propertyNotWritable(asyncResp->res, "MaxPasswordLength");
+ }
+
+ if (ldapObject)
+ {
+ handleLDAPPatch(*ldapObject, asyncResp, "LDAP");
+ }
+
+ if (std::optional<nlohmann::json> oemOpenBMCObject;
+ oemObject && json_util::readJson(*oemObject, asyncResp->res, "OpenBMC",
+ oemOpenBMCObject))
+ {
+ if (std::optional<nlohmann::json> authMethodsObject;
+ oemOpenBMCObject &&
+ json_util::readJson(*oemOpenBMCObject, asyncResp->res,
+ "AuthMethods", authMethodsObject))
+ {
+ if (authMethodsObject)
+ {
+ handleAuthMethodsPatch(*authMethodsObject, asyncResp);
+ }
+ }
+ }
+
+ if (activeDirectoryObject)
+ {
+ handleLDAPPatch(*activeDirectoryObject, asyncResp, "ActiveDirectory");
+ }
+
+ if (unlockTimeout)
+ {
+ crow::connections::systemBus->async_method_call(
+ [asyncResp](const boost::system::error_code ec) {
+ if (ec)
+ {
+ messages::internalError(asyncResp->res);
+ return;
+ }
+ messages::success(asyncResp->res);
+ },
+ "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
+ "org.freedesktop.DBus.Properties", "Set",
+ "xyz.openbmc_project.User.AccountPolicy", "AccountUnlockTimeout",
+ dbus::utility::DbusVariantType(*unlockTimeout));
+ }
+ if (lockoutThreshold)
+ {
+ crow::connections::systemBus->async_method_call(
+ [asyncResp](const boost::system::error_code ec) {
+ if (ec)
+ {
+ messages::internalError(asyncResp->res);
+ return;
+ }
+ messages::success(asyncResp->res);
+ },
+ "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
+ "org.freedesktop.DBus.Properties", "Set",
+ "xyz.openbmc_project.User.AccountPolicy",
+ "MaxLoginAttemptBeforeLockout",
+ dbus::utility::DbusVariantType(*lockoutThreshold));
+ }
+}
+
+inline void handleAccountCollectionGet(
+ App& app, const crow::Request& req,
+ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
+{
+ if (!redfish::setUpRedfishRoute(app, req, asyncResp))
+ {
+ return;
+ }
+
+ asyncResp->res.jsonValue["@odata.id"] =
+ "/redfish/v1/AccountService/Accounts";
+ asyncResp->res.jsonValue["@odata.type"] = "#ManagerAccountCollection."
+ "ManagerAccountCollection";
+ asyncResp->res.jsonValue["Name"] = "Accounts Collection";
+ asyncResp->res.jsonValue["Description"] = "BMC User Accounts";
+
+ Privileges effectiveUserPrivileges =
+ redfish::getUserPrivileges(req.userRole);
+
+ std::string thisUser;
+ if (req.session)
+ {
+ thisUser = req.session->username;
+ }
+ crow::connections::systemBus->async_method_call(
+ [asyncResp, thisUser, effectiveUserPrivileges](
+ const boost::system::error_code ec,
+ const dbus::utility::ManagedObjectType& users) {
+ if (ec)
+ {
+ messages::internalError(asyncResp->res);
+ return;
+ }
+
+ bool userCanSeeAllAccounts =
+ effectiveUserPrivileges.isSupersetOf({"ConfigureUsers"});
+
+ bool userCanSeeSelf =
+ effectiveUserPrivileges.isSupersetOf({"ConfigureSelf"});
+
+ nlohmann::json& memberArray = asyncResp->res.jsonValue["Members"];
+ memberArray = nlohmann::json::array();
+
+ for (const auto& userpath : users)
+ {
+ std::string user = userpath.first.filename();
+ if (user.empty())
+ {
+ messages::internalError(asyncResp->res);
+ BMCWEB_LOG_ERROR << "Invalid firmware ID";
+
+ return;
+ }
+
+ // As clarified by Redfish here:
+ // https://redfishforum.com/thread/281/manageraccountcollection-change-allows-account-enumeration
+ // Users without ConfigureUsers, only see their own
+ // account. Users with ConfigureUsers, see all
+ // accounts.
+ if (userCanSeeAllAccounts || (thisUser == user && userCanSeeSelf))
+ {
+ nlohmann::json::object_t member;
+ member["@odata.id"] =
+ "/redfish/v1/AccountService/Accounts/" + user;
+ memberArray.push_back(std::move(member));
+ }
+ }
+ asyncResp->res.jsonValue["Members@odata.count"] = memberArray.size();
+ },
+ "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
+ "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
+}
+
+inline void handleAccountCollectionPost(
+ App& app, const crow::Request& req,
+ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
+{
+ if (!redfish::setUpRedfishRoute(app, req, asyncResp))
+ {
+ return;
+ }
+ std::string username;
+ std::string password;
+ std::optional<std::string> roleId("User");
+ std::optional<bool> enabled = true;
+ if (!json_util::readJsonPatch(req, asyncResp->res, "UserName", username,
+ "Password", password, "RoleId", roleId,
+ "Enabled", enabled))
+ {
+ return;
+ }
+
+ std::string priv = getPrivilegeFromRoleId(*roleId);
+ if (priv.empty())
+ {
+ messages::propertyValueNotInList(asyncResp->res, *roleId, "RoleId");
+ return;
+ }
+ // TODO: Following override will be reverted once support in
+ // phosphor-user-manager is added. In order to avoid dependency
+ // issues, this is added in bmcweb, which will removed, once
+ // phosphor-user-manager supports priv-noaccess.
+ if (priv == "priv-noaccess")
+ {
+ roleId = "";
+ }
+ else
+ {
+ roleId = priv;
+ }
+
+ // Reading AllGroups property
+ sdbusplus::asio::getProperty<std::vector<std::string>>(
+ *crow::connections::systemBus, "xyz.openbmc_project.User.Manager",
+ "/xyz/openbmc_project/user", "xyz.openbmc_project.User.Manager",
+ "AllGroups",
+ [asyncResp, username, password{std::move(password)}, roleId,
+ enabled](const boost::system::error_code ec,
+ const std::vector<std::string>& allGroupsList) {
+ if (ec)
+ {
+ BMCWEB_LOG_DEBUG << "ERROR with async_method_call";
+ messages::internalError(asyncResp->res);
+ return;
+ }
+
+ if (allGroupsList.empty())
+ {
+ messages::internalError(asyncResp->res);
+ return;
+ }
+
+ crow::connections::systemBus->async_method_call(
+ [asyncResp, username, password](const boost::system::error_code ec2,
+ sdbusplus::message::message& m) {
+ if (ec2)
+ {
+ userErrorMessageHandler(m.get_error(), asyncResp, username, "");
+ return;
+ }
+
+ if (pamUpdatePassword(username, password) != PAM_SUCCESS)
+ {
+ // At this point we have a user that's been
+ // created, but the password set
+ // failed.Something is wrong, so delete the user
+ // that we've already created
+ sdbusplus::message::object_path tempObjPath(rootUserDbusPath);
+ tempObjPath /= username;
+ const std::string userPath(tempObjPath);
+
+ crow::connections::systemBus->async_method_call(
+ [asyncResp, password](const boost::system::error_code ec3) {
+ if (ec3)
+ {
+ messages::internalError(asyncResp->res);
+ return;
+ }
+
+ // If password is invalid
+ messages::propertyValueFormatError(asyncResp->res, password,
+ "Password");
+ },
+ "xyz.openbmc_project.User.Manager", userPath,
+ "xyz.openbmc_project.Object.Delete", "Delete");
+
+ BMCWEB_LOG_ERROR << "pamUpdatePassword Failed";
+ return;
+ }
+
+ messages::created(asyncResp->res);
+ asyncResp->res.addHeader(
+ "Location", "/redfish/v1/AccountService/Accounts/" + username);
+ },
+ "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
+ "xyz.openbmc_project.User.Manager", "CreateUser", username,
+ allGroupsList, *roleId, *enabled);
+ });
+}
+
+inline void
+ handleAccountGet(App& app, const crow::Request& req,
+ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+ const std::string& accountName)
+{
+ if (!redfish::setUpRedfishRoute(app, req, asyncResp))
+ {
+ return;
+ }
+#ifdef BMCWEB_INSECURE_DISABLE_AUTHENTICATION
+ // If authentication is disabled, there are no user accounts
+ messages::resourceNotFound(
+ asyncResp->res, "#ManagerAccount.v1_4_0.ManagerAccount", accountName);
+ return;
+
+#endif // BMCWEB_INSECURE_DISABLE_AUTHENTICATION
+ if (req.session == nullptr)
+ {
+ messages::internalError(asyncResp->res);
+ return;
+ }
+ if (req.session->username != accountName)
+ {
+ // At this point we've determined that the user is trying to
+ // modify a user that isn't them. We need to verify that they
+ // have permissions to modify other users, so re-run the auth
+ // check with the same permissions, minus ConfigureSelf.
+ Privileges effectiveUserPrivileges =
+ redfish::getUserPrivileges(req.userRole);
+ Privileges requiredPermissionsToChangeNonSelf = {"ConfigureUsers",
+ "ConfigureManager"};
+ if (!effectiveUserPrivileges.isSupersetOf(
+ requiredPermissionsToChangeNonSelf))
+ {
+ BMCWEB_LOG_DEBUG << "GET Account denied access";
+ messages::insufficientPrivilege(asyncResp->res);
+ return;
+ }
+ }
+
+ crow::connections::systemBus->async_method_call(
+ [asyncResp,
+ accountName](const boost::system::error_code ec,
+ const dbus::utility::ManagedObjectType& users) {
+ if (ec)
+ {
+ messages::internalError(asyncResp->res);
+ return;
+ }
+ const auto userIt = std::find_if(
+ users.begin(), users.end(),
+ [accountName](
+ const std::pair<sdbusplus::message::object_path,
+ dbus::utility::DBusInteracesMap>& user) {
+ return accountName == user.first.filename();
+ });
+
+ if (userIt == users.end())
+ {
+ messages::resourceNotFound(asyncResp->res, "ManagerAccount",
+ accountName);
+ return;
+ }
+
+ asyncResp->res.jsonValue["@odata.type"] =
+ "#ManagerAccount.v1_4_0.ManagerAccount";
+ asyncResp->res.jsonValue["Name"] = "User Account";
+ asyncResp->res.jsonValue["Description"] = "User Account";
+ asyncResp->res.jsonValue["Password"] = nullptr;
+ asyncResp->res.jsonValue["AccountTypes"] = {"Redfish"};
+
+ for (const auto& interface : userIt->second)
+ {
+ if (interface.first == "xyz.openbmc_project.User.Attributes")
+ {
+ for (const auto& property : interface.second)
+ {
+ if (property.first == "UserEnabled")
+ {
+ const bool* userEnabled =
+ std::get_if<bool>(&property.second);
+ if (userEnabled == nullptr)
+ {
+ BMCWEB_LOG_ERROR << "UserEnabled wasn't a bool";
+ messages::internalError(asyncResp->res);
+ return;
+ }
+ asyncResp->res.jsonValue["Enabled"] = *userEnabled;
+ }
+ else if (property.first == "UserLockedForFailedAttempt")
+ {
+ const bool* userLocked =
+ std::get_if<bool>(&property.second);
+ if (userLocked == nullptr)
+ {
+ BMCWEB_LOG_ERROR << "UserLockedForF"
+ "ailedAttempt "
+ "wasn't a bool";
+ messages::internalError(asyncResp->res);
+ return;
+ }
+ asyncResp->res.jsonValue["Locked"] = *userLocked;
+ asyncResp->res
+ .jsonValue["Locked@Redfish.AllowableValues"] = {
+ "false"}; // can only unlock accounts
+ }
+ else if (property.first == "UserPrivilege")
+ {
+ const std::string* userPrivPtr =
+ std::get_if<std::string>(&property.second);
+ if (userPrivPtr == nullptr)
+ {
+ BMCWEB_LOG_ERROR << "UserPrivilege wasn't a "
+ "string";
+ messages::internalError(asyncResp->res);
+ return;
+ }
+ std::string role = getRoleIdFromPrivilege(*userPrivPtr);
+ if (role.empty())
+ {
+ BMCWEB_LOG_ERROR << "Invalid user role";
+ messages::internalError(asyncResp->res);
+ return;
+ }
+ asyncResp->res.jsonValue["RoleId"] = role;
+
+ nlohmann::json& roleEntry =
+ asyncResp->res.jsonValue["Links"]["Role"];
+ roleEntry["@odata.id"] =
+ "/redfish/v1/AccountService/Roles/" + role;
+ }
+ else if (property.first == "UserPasswordExpired")
+ {
+ const bool* userPasswordExpired =
+ std::get_if<bool>(&property.second);
+ if (userPasswordExpired == nullptr)
+ {
+ BMCWEB_LOG_ERROR
+ << "UserPasswordExpired wasn't a bool";
+ messages::internalError(asyncResp->res);
+ return;
+ }
+ asyncResp->res.jsonValue["PasswordChangeRequired"] =
+ *userPasswordExpired;
+ }
+ }
+ }
+ }
+
+ asyncResp->res.jsonValue["@odata.id"] =
+ "/redfish/v1/AccountService/Accounts/" + accountName;
+ asyncResp->res.jsonValue["Id"] = accountName;
+ asyncResp->res.jsonValue["UserName"] = accountName;
+ },
+ "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
+ "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
+}
+
+inline void
+ handleAccounttDelete(App& app, const crow::Request& req,
+ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+ const std::string& username)
+{
+ if (!redfish::setUpRedfishRoute(app, req, asyncResp))
+ {
+ return;
+ }
+
+#ifdef BMCWEB_INSECURE_DISABLE_AUTHENTICATION
+ // If authentication is disabled, there are no user accounts
+ messages::resourceNotFound(
+ asyncResp->res, "#ManagerAccount.v1_4_0.ManagerAccount", username);
+ return;
+
+#endif // BMCWEB_INSECURE_DISABLE_AUTHENTICATION
+ sdbusplus::message::object_path tempObjPath(rootUserDbusPath);
+ tempObjPath /= username;
+ const std::string userPath(tempObjPath);
+
+ crow::connections::systemBus->async_method_call(
+ [asyncResp, username](const boost::system::error_code ec) {
+ if (ec)
+ {
+ messages::resourceNotFound(asyncResp->res,
+ "#ManagerAccount.v1_4_0.ManagerAccount",
+ username);
+ return;
+ }
+
+ messages::accountRemoved(asyncResp->res);
+ },
+ "xyz.openbmc_project.User.Manager", userPath,
+ "xyz.openbmc_project.Object.Delete", "Delete");
+}
+
+inline void
+ handleAccountPatch(App& app, const crow::Request& req,
+ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+ const std::string& username)
+{
+ if (!redfish::setUpRedfishRoute(app, req, asyncResp))
+ {
+ return;
+ }
+#ifdef BMCWEB_INSECURE_DISABLE_AUTHENTICATION
+ // If authentication is disabled, there are no user accounts
+ messages::resourceNotFound(
+ asyncResp->res, "#ManagerAccount.v1_4_0.ManagerAccount", username);
+ return;
+
+#endif // BMCWEB_INSECURE_DISABLE_AUTHENTICATION
+ std::optional<std::string> newUserName;
+ std::optional<std::string> password;
+ std::optional<bool> enabled;
+ std::optional<std::string> roleId;
+ std::optional<bool> locked;
+
+ if (req.session == nullptr)
+ {
+ messages::internalError(asyncResp->res);
+ return;
+ }
+
+ Privileges effectiveUserPrivileges =
+ redfish::getUserPrivileges(req.userRole);
+ Privileges configureUsers = {"ConfigureUsers"};
+ bool userHasConfigureUsers =
+ effectiveUserPrivileges.isSupersetOf(configureUsers);
+ if (userHasConfigureUsers)
+ {
+ // Users with ConfigureUsers can modify for all users
+ if (!json_util::readJsonPatch(req, asyncResp->res, "UserName",
+ newUserName, "Password", password,
+ "RoleId", roleId, "Enabled", enabled,
+ "Locked", locked))
+ {
+ return;
+ }
+ }
+ else
+ {
+ // ConfigureSelf accounts can only modify their own account
+ if (username != req.session->username)
+ {
+ messages::insufficientPrivilege(asyncResp->res);
+ return;
+ }
+
+ // ConfigureSelf accounts can only modify their password
+ if (!json_util::readJsonPatch(req, asyncResp->res, "Password",
+ password))
+ {
+ return;
+ }
+ }
+
+ // if user name is not provided in the patch method or if it
+ // matches the user name in the URI, then we are treating it as
+ // updating user properties other then username. If username
+ // provided doesn't match the URI, then we are treating this as
+ // user rename request.
+ if (!newUserName || (newUserName.value() == username))
+ {
+ updateUserProperties(asyncResp, username, password, enabled, roleId,
+ locked);
+ return;
+ }
+ crow::connections::systemBus->async_method_call(
+ [asyncResp, username, password(std::move(password)),
+ roleId(std::move(roleId)), enabled, newUser{std::string(*newUserName)},
+ locked](const boost::system::error_code ec,
+ sdbusplus::message::message& m) {
+ if (ec)
+ {
+ userErrorMessageHandler(m.get_error(), asyncResp, newUser,
+ username);
+ return;
+ }
+
+ updateUserProperties(asyncResp, newUser, password, enabled, roleId,
+ locked);
+ },
+ "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
+ "xyz.openbmc_project.User.Manager", "RenameUser", username,
+ *newUserName);
+}
+
inline void requestAccountServiceRoutes(App& app)
{
BMCWEB_ROUTE(app, "/redfish/v1/AccountService/")
.privileges(redfish::privileges::getAccountService)
.methods(boost::beast::http::verb::get)(
- [&app](
- const crow::Request& req,
- const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) -> void {
- if (!redfish::setUpRedfishRoute(app, req, asyncResp))
- {
- return;
- }
- const persistent_data::AuthConfigMethods& authMethodsConfig =
- persistent_data::SessionStore::getInstance()
- .getAuthMethodsConfig();
-
- nlohmann::json& json = asyncResp->res.jsonValue;
- json["@odata.id"] = "/redfish/v1/AccountService";
- json["@odata.type"] = "#AccountService."
- "v1_10_0.AccountService";
- json["Id"] = "AccountService";
- json["Name"] = "Account Service";
- json["Description"] = "Account Service";
- json["ServiceEnabled"] = true;
- json["MaxPasswordLength"] = 20;
- json["Accounts"]["@odata.id"] =
- "/redfish/v1/AccountService/Accounts";
- json["Roles"]["@odata.id"] = "/redfish/v1/AccountService/Roles";
- json["Oem"]["OpenBMC"]["@odata.type"] =
- "#OemAccountService.v1_0_0.AccountService";
- json["Oem"]["OpenBMC"]["@odata.id"] =
- "/redfish/v1/AccountService#/Oem/OpenBMC";
- json["Oem"]["OpenBMC"]["AuthMethods"]["BasicAuth"] =
- authMethodsConfig.basic;
- json["Oem"]["OpenBMC"]["AuthMethods"]["SessionToken"] =
- authMethodsConfig.sessionToken;
- json["Oem"]["OpenBMC"]["AuthMethods"]["XToken"] =
- authMethodsConfig.xtoken;
- json["Oem"]["OpenBMC"]["AuthMethods"]["Cookie"] =
- authMethodsConfig.cookie;
- json["Oem"]["OpenBMC"]["AuthMethods"]["TLS"] =
- authMethodsConfig.tls;
-
- // /redfish/v1/AccountService/LDAP/Certificates is something
- // only ConfigureManager can access then only display when the
- // user has permissions ConfigureManager
- Privileges effectiveUserPrivileges =
- redfish::getUserPrivileges(req.userRole);
-
- if (isOperationAllowedWithPrivileges({{"ConfigureManager"}},
- effectiveUserPrivileges))
- {
- asyncResp->res
- .jsonValue["LDAP"]["Certificates"]["@odata.id"] =
- "/redfish/v1/AccountService/LDAP/Certificates";
- }
- crow::connections::systemBus->async_method_call(
- [asyncResp](const boost::system::error_code ec,
- const dbus::utility::DBusPropertiesMap&
- propertiesList) {
- if (ec)
- {
- messages::internalError(asyncResp->res);
- return;
- }
- BMCWEB_LOG_DEBUG << "Got " << propertiesList.size()
- << "properties for AccountService";
- for (const std::pair<std::string, dbus::utility::DbusVariantType>&
- property : propertiesList)
- {
- if (property.first == "MinPasswordLength")
- {
- const uint8_t* value =
- std::get_if<uint8_t>(&property.second);
- if (value != nullptr)
- {
- asyncResp->res.jsonValue["MinPasswordLength"] = *value;
- }
- }
- if (property.first == "AccountUnlockTimeout")
- {
- const uint32_t* value =
- std::get_if<uint32_t>(&property.second);
- if (value != nullptr)
- {
- asyncResp->res.jsonValue["AccountLockoutDuration"] =
- *value;
- }
- }
- if (property.first == "MaxLoginAttemptBeforeLockout")
- {
- const uint16_t* value =
- std::get_if<uint16_t>(&property.second);
- if (value != nullptr)
- {
- asyncResp->res.jsonValue["AccountLockoutThreshold"] =
- *value;
- }
- }
- }
- },
- "xyz.openbmc_project.User.Manager",
- "/xyz/openbmc_project/user",
- "org.freedesktop.DBus.Properties", "GetAll",
- "xyz.openbmc_project.User.AccountPolicy");
-
- auto callback =
- [asyncResp](bool success, LDAPConfigData& confData,
- const std::string& ldapType) {
- if (!success)
- {
- return;
- }
- parseLDAPConfigData(asyncResp->res.jsonValue, confData, ldapType);
- };
-
- getLDAPConfigData("LDAP", callback);
- getLDAPConfigData("ActiveDirectory", callback);
- });
+ std::bind_front(handleAccountServiceGet, std::ref(app)));
BMCWEB_ROUTE(app, "/redfish/v1/AccountService/")
.privileges(redfish::privileges::patchAccountService)
.methods(boost::beast::http::verb::patch)(
- [&app](
- const crow::Request& req,
- const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) -> void {
- if (!redfish::setUpRedfishRoute(app, req, asyncResp))
- {
- return;
- }
- std::optional<uint32_t> unlockTimeout;
- std::optional<uint16_t> lockoutThreshold;
- std::optional<uint8_t> minPasswordLength;
- std::optional<uint16_t> maxPasswordLength;
- std::optional<nlohmann::json> ldapObject;
- std::optional<nlohmann::json> activeDirectoryObject;
- std::optional<nlohmann::json> oemObject;
-
- if (!json_util::readJsonPatch(
- req, asyncResp->res, "AccountLockoutDuration",
- unlockTimeout, "AccountLockoutThreshold",
- lockoutThreshold, "MaxPasswordLength",
- maxPasswordLength, "MinPasswordLength",
- minPasswordLength, "LDAP", ldapObject,
- "ActiveDirectory", activeDirectoryObject, "Oem",
- oemObject))
- {
- return;
- }
-
- if (minPasswordLength)
- {
- crow::connections::systemBus->async_method_call(
- [asyncResp](const boost::system::error_code ec) {
- if (ec)
- {
- messages::internalError(asyncResp->res);
- return;
- }
- messages::success(asyncResp->res);
- },
- "xyz.openbmc_project.User.Manager",
- "/xyz/openbmc_project/user",
- "org.freedesktop.DBus.Properties", "Set",
- "xyz.openbmc_project.User.AccountPolicy",
- "MinPasswordLength",
- dbus::utility::DbusVariantType(*minPasswordLength));
- }
-
- if (maxPasswordLength)
- {
- messages::propertyNotWritable(asyncResp->res,
- "MaxPasswordLength");
- }
-
- if (ldapObject)
- {
- handleLDAPPatch(*ldapObject, asyncResp, "LDAP");
- }
-
- if (std::optional<nlohmann::json> oemOpenBMCObject;
- oemObject &&
- json_util::readJson(*oemObject, asyncResp->res, "OpenBMC",
- oemOpenBMCObject))
- {
- if (std::optional<nlohmann::json> authMethodsObject;
- oemOpenBMCObject &&
- json_util::readJson(*oemOpenBMCObject, asyncResp->res,
- "AuthMethods", authMethodsObject))
- {
- if (authMethodsObject)
- {
- handleAuthMethodsPatch(*authMethodsObject,
- asyncResp);
- }
- }
- }
-
- if (activeDirectoryObject)
- {
- handleLDAPPatch(*activeDirectoryObject, asyncResp,
- "ActiveDirectory");
- }
-
- if (unlockTimeout)
- {
- crow::connections::systemBus->async_method_call(
- [asyncResp](const boost::system::error_code ec) {
- if (ec)
- {
- messages::internalError(asyncResp->res);
- return;
- }
- messages::success(asyncResp->res);
- },
- "xyz.openbmc_project.User.Manager",
- "/xyz/openbmc_project/user",
- "org.freedesktop.DBus.Properties", "Set",
- "xyz.openbmc_project.User.AccountPolicy",
- "AccountUnlockTimeout",
- dbus::utility::DbusVariantType(*unlockTimeout));
- }
- if (lockoutThreshold)
- {
- crow::connections::systemBus->async_method_call(
- [asyncResp](const boost::system::error_code ec) {
- if (ec)
- {
- messages::internalError(asyncResp->res);
- return;
- }
- messages::success(asyncResp->res);
- },
- "xyz.openbmc_project.User.Manager",
- "/xyz/openbmc_project/user",
- "org.freedesktop.DBus.Properties", "Set",
- "xyz.openbmc_project.User.AccountPolicy",
- "MaxLoginAttemptBeforeLockout",
- dbus::utility::DbusVariantType(*lockoutThreshold));
- }
- });
+ std::bind_front(handleAccountServicePatch, std::ref(app)));
BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/")
.privileges(redfish::privileges::getManagerAccountCollection)
.methods(boost::beast::http::verb::get)(
- [&app](
- const crow::Request& req,
- const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) -> void {
- if (!redfish::setUpRedfishRoute(app, req, asyncResp))
- {
- return;
- }
-
- asyncResp->res.jsonValue["@odata.id"] =
- "/redfish/v1/AccountService/Accounts";
- asyncResp->res.jsonValue["@odata.type"] =
- "#ManagerAccountCollection."
- "ManagerAccountCollection";
- asyncResp->res.jsonValue["Name"] = "Accounts Collection";
- asyncResp->res.jsonValue["Description"] = "BMC User Accounts";
-
- Privileges effectiveUserPrivileges =
- redfish::getUserPrivileges(req.userRole);
-
- std::string thisUser;
- if (req.session)
- {
- thisUser = req.session->username;
- }
- crow::connections::systemBus->async_method_call(
- [asyncResp, thisUser, effectiveUserPrivileges](
- const boost::system::error_code ec,
- const dbus::utility::ManagedObjectType& users) {
- if (ec)
- {
- messages::internalError(asyncResp->res);
- return;
- }
-
- bool userCanSeeAllAccounts =
- effectiveUserPrivileges.isSupersetOf({"ConfigureUsers"});
-
- bool userCanSeeSelf =
- effectiveUserPrivileges.isSupersetOf({"ConfigureSelf"});
-
- nlohmann::json& memberArray = asyncResp->res.jsonValue["Members"];
- memberArray = nlohmann::json::array();
-
- for (const auto& userpath : users)
- {
- std::string user = userpath.first.filename();
- if (user.empty())
- {
- messages::internalError(asyncResp->res);
- BMCWEB_LOG_ERROR << "Invalid firmware ID";
-
- return;
- }
-
- // As clarified by Redfish here:
- // https://redfishforum.com/thread/281/manageraccountcollection-change-allows-account-enumeration
- // Users without ConfigureUsers, only see their own
- // account. Users with ConfigureUsers, see all
- // accounts.
- if (userCanSeeAllAccounts ||
- (thisUser == user && userCanSeeSelf))
- {
- nlohmann::json::object_t member;
- member["@odata.id"] =
- "/redfish/v1/AccountService/Accounts/" + user;
- memberArray.push_back(std::move(member));
- }
- }
- asyncResp->res.jsonValue["Members@odata.count"] =
- memberArray.size();
- },
- "xyz.openbmc_project.User.Manager",
- "/xyz/openbmc_project/user",
- "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
- });
+ std::bind_front(handleAccountCollectionGet, std::ref(app)));
BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/")
.privileges(redfish::privileges::postManagerAccountCollection)
.methods(boost::beast::http::verb::post)(
- [&app](
- const crow::Request& req,
- const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) -> void {
- if (!redfish::setUpRedfishRoute(app, req, asyncResp))
- {
- return;
- }
- std::string username;
- std::string password;
- std::optional<std::string> roleId("User");
- std::optional<bool> enabled = true;
- if (!json_util::readJsonPatch(
- req, asyncResp->res, "UserName", username, "Password",
- password, "RoleId", roleId, "Enabled", enabled))
- {
- return;
- }
-
- std::string priv = getPrivilegeFromRoleId(*roleId);
- if (priv.empty())
- {
- messages::propertyValueNotInList(asyncResp->res, *roleId,
- "RoleId");
- return;
- }
- // TODO: Following override will be reverted once support in
- // phosphor-user-manager is added. In order to avoid dependency
- // issues, this is added in bmcweb, which will removed, once
- // phosphor-user-manager supports priv-noaccess.
- if (priv == "priv-noaccess")
- {
- roleId = "";
- }
- else
- {
- roleId = priv;
- }
-
- // Reading AllGroups property
- sdbusplus::asio::getProperty<std::vector<std::string>>(
- *crow::connections::systemBus,
- "xyz.openbmc_project.User.Manager",
- "/xyz/openbmc_project/user",
- "xyz.openbmc_project.User.Manager", "AllGroups",
- [asyncResp, username, password{std::move(password)}, roleId,
- enabled](const boost::system::error_code ec,
- const std::vector<std::string>& allGroupsList) {
- if (ec)
- {
- BMCWEB_LOG_DEBUG << "ERROR with async_method_call";
- messages::internalError(asyncResp->res);
- return;
- }
-
- if (allGroupsList.empty())
- {
- messages::internalError(asyncResp->res);
- return;
- }
-
- crow::connections::systemBus->async_method_call(
- [asyncResp, username,
- password](const boost::system::error_code ec2,
- sdbusplus::message::message& m) {
- if (ec2)
- {
- userErrorMessageHandler(m.get_error(), asyncResp, username,
- "");
- return;
- }
-
- if (pamUpdatePassword(username, password) != PAM_SUCCESS)
- {
- // At this point we have a user that's been
- // created, but the password set
- // failed.Something is wrong, so delete the user
- // that we've already created
- sdbusplus::message::object_path tempObjPath(
- rootUserDbusPath);
- tempObjPath /= username;
- const std::string userPath(tempObjPath);
-
- crow::connections::systemBus->async_method_call(
- [asyncResp,
- password](const boost::system::error_code ec3) {
- if (ec3)
- {
- messages::internalError(asyncResp->res);
- return;
- }
-
- // If password is invalid
- messages::propertyValueFormatError(
- asyncResp->res, password, "Password");
- },
- "xyz.openbmc_project.User.Manager", userPath,
- "xyz.openbmc_project.Object.Delete", "Delete");
-
- BMCWEB_LOG_ERROR << "pamUpdatePassword Failed";
- return;
- }
-
- messages::created(asyncResp->res);
- asyncResp->res.addHeader(
- "Location",
- "/redfish/v1/AccountService/Accounts/" + username);
- },
- "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
- "xyz.openbmc_project.User.Manager", "CreateUser", username,
- allGroupsList, *roleId, *enabled);
- });
- });
+ std::bind_front(handleAccountCollectionPost, std::ref(app)));
BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/<str>/")
.privileges(redfish::privileges::getManagerAccount)
.methods(boost::beast::http::verb::get)(
- [&app]([[maybe_unused]] const crow::Request& req,
- const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
- const std::string& accountName) -> void {
- if (!redfish::setUpRedfishRoute(app, req, asyncResp))
- {
- return;
- }
-#ifdef BMCWEB_INSECURE_DISABLE_AUTHX
- // If authentication is disabled, there are no user accounts
- messages::resourceNotFound(
- asyncResp->res, "#ManagerAccount.v1_4_0.ManagerAccount",
- accountName);
- return;
-
-#endif // BMCWEB_INSECURE_DISABLE_AUTHX
- if (req.session == nullptr)
- {
- messages::internalError(asyncResp->res);
- return;
- }
- if (req.session->username != accountName)
- {
- // At this point we've determined that the user is trying to
- // modify a user that isn't them. We need to verify that
- // they have permissions to modify other users, so re-run
- // the auth check with the same permissions, minus
- // ConfigureSelf.
- Privileges effectiveUserPrivileges =
- redfish::getUserPrivileges(req.userRole);
- Privileges requiredPermissionsToChangeNonSelf = {
- "ConfigureUsers", "ConfigureManager"};
- if (!effectiveUserPrivileges.isSupersetOf(
- requiredPermissionsToChangeNonSelf))
- {
- BMCWEB_LOG_DEBUG << "GET Account denied access";
- messages::insufficientPrivilege(asyncResp->res);
- return;
- }
- }
-
- crow::connections::systemBus->async_method_call(
- [asyncResp, accountName](
- const boost::system::error_code ec,
- const dbus::utility::ManagedObjectType& users) {
- if (ec)
- {
- messages::internalError(asyncResp->res);
- return;
- }
- const auto userIt = std::find_if(
- users.begin(), users.end(),
- [accountName](
- const std::pair<sdbusplus::message::object_path,
- dbus::utility::DBusInteracesMap>& user) {
- return accountName == user.first.filename();
- });
-
- if (userIt == users.end())
- {
- messages::resourceNotFound(asyncResp->res, "ManagerAccount",
- accountName);
- return;
- }
-
- asyncResp->res.jsonValue["@odata.type"] =
- "#ManagerAccount.v1_4_0.ManagerAccount";
- asyncResp->res.jsonValue["Name"] = "User Account";
- asyncResp->res.jsonValue["Description"] = "User Account";
- asyncResp->res.jsonValue["Password"] = nullptr;
- asyncResp->res.jsonValue["AccountTypes"] = {"Redfish"};
-
- for (const auto& interface : userIt->second)
- {
- if (interface.first == "xyz.openbmc_project.User.Attributes")
- {
- for (const auto& property : interface.second)
- {
- if (property.first == "UserEnabled")
- {
- const bool* userEnabled =
- std::get_if<bool>(&property.second);
- if (userEnabled == nullptr)
- {
- BMCWEB_LOG_ERROR << "UserEnabled wasn't a bool";
- messages::internalError(asyncResp->res);
- return;
- }
- asyncResp->res.jsonValue["Enabled"] = *userEnabled;
- }
- else if (property.first == "UserLockedForFailedAttempt")
- {
- const bool* userLocked =
- std::get_if<bool>(&property.second);
- if (userLocked == nullptr)
- {
- BMCWEB_LOG_ERROR << "UserLockedForF"
- "ailedAttempt "
- "wasn't a bool";
- messages::internalError(asyncResp->res);
- return;
- }
- asyncResp->res.jsonValue["Locked"] = *userLocked;
- asyncResp->res
- .jsonValue["Locked@Redfish.AllowableValues"] = {
- "false"}; // can only unlock accounts
- }
- else if (property.first == "UserPrivilege")
- {
- const std::string* userPrivPtr =
- std::get_if<std::string>(&property.second);
- if (userPrivPtr == nullptr)
- {
- BMCWEB_LOG_ERROR << "UserPrivilege wasn't a "
- "string";
- messages::internalError(asyncResp->res);
- return;
- }
- std::string role =
- getRoleIdFromPrivilege(*userPrivPtr);
- if (role.empty())
- {
- BMCWEB_LOG_ERROR << "Invalid user role";
- messages::internalError(asyncResp->res);
- return;
- }
- asyncResp->res.jsonValue["RoleId"] = role;
-
- nlohmann::json& roleEntry =
- asyncResp->res.jsonValue["Links"]["Role"];
- roleEntry["@odata.id"] =
- "/redfish/v1/AccountService/Roles/" + role;
- }
- else if (property.first == "UserPasswordExpired")
- {
- const bool* userPasswordExpired =
- std::get_if<bool>(&property.second);
- if (userPasswordExpired == nullptr)
- {
- BMCWEB_LOG_ERROR
- << "UserPasswordExpired wasn't a bool";
- messages::internalError(asyncResp->res);
- return;
- }
- asyncResp->res.jsonValue["PasswordChangeRequired"] =
- *userPasswordExpired;
- }
- }
- }
- }
-
- asyncResp->res.jsonValue["@odata.id"] =
- "/redfish/v1/AccountService/Accounts/" + accountName;
- asyncResp->res.jsonValue["Id"] = accountName;
- asyncResp->res.jsonValue["UserName"] = accountName;
- },
- "xyz.openbmc_project.User.Manager",
- "/xyz/openbmc_project/user",
- "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
- });
+ std::bind_front(handleAccountGet, std::ref(app)));
BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/<str>/")
// TODO this privilege should be using the generated endpoints, but
@@ -1845,137 +1951,12 @@
// yet
.privileges({{"ConfigureUsers"}, {"ConfigureSelf"}})
.methods(boost::beast::http::verb::patch)(
- [&app](const crow::Request& req,
- const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
- const std::string& username) -> void {
- if (!redfish::setUpRedfishRoute(app, req, asyncResp))
- {
- return;
- }
-#ifdef BMCWEB_INSECURE_DISABLE_AUTHX
- // If authentication is disabled, there are no user accounts
- messages::resourceNotFound(
- asyncResp->res, "#ManagerAccount.v1_4_0.ManagerAccount",
- username);
- return;
-
-#endif // BMCWEB_INSECURE_DISABLE_AUTHX
- std::optional<std::string> newUserName;
- std::optional<std::string> password;
- std::optional<bool> enabled;
- std::optional<std::string> roleId;
- std::optional<bool> locked;
-
- if (req.session == nullptr)
- {
- messages::internalError(asyncResp->res);
- return;
- }
-
- Privileges effectiveUserPrivileges =
- redfish::getUserPrivileges(req.userRole);
- Privileges configureUsers = {"ConfigureUsers"};
- bool userHasConfigureUsers =
- effectiveUserPrivileges.isSupersetOf(configureUsers);
- if (userHasConfigureUsers)
- {
- // Users with ConfigureUsers can modify for all users
- if (!json_util::readJsonPatch(
- req, asyncResp->res, "UserName", newUserName,
- "Password", password, "RoleId", roleId, "Enabled",
- enabled, "Locked", locked))
- {
- return;
- }
- }
- else
- {
- // ConfigureSelf accounts can only modify their own account
- if (username != req.session->username)
- {
- messages::insufficientPrivilege(asyncResp->res);
- return;
- }
-
- // ConfigureSelf accounts can only modify their password
- if (!json_util::readJsonPatch(req, asyncResp->res,
- "Password", password))
- {
- return;
- }
- }
-
- // if user name is not provided in the patch method or if it
- // matches the user name in the URI, then we are treating it as
- // updating user properties other then username. If username
- // provided doesn't match the URI, then we are treating this as
- // user rename request.
- if (!newUserName || (newUserName.value() == username))
- {
- updateUserProperties(asyncResp, username, password, enabled,
- roleId, locked);
- return;
- }
- crow::connections::systemBus->async_method_call(
- [asyncResp, username, password(std::move(password)),
- roleId(std::move(roleId)), enabled,
- newUser{std::string(*newUserName)},
- locked](const boost::system::error_code ec,
- sdbusplus::message::message& m) {
- if (ec)
- {
- userErrorMessageHandler(m.get_error(), asyncResp, newUser,
- username);
- return;
- }
-
- updateUserProperties(asyncResp, newUser, password, enabled, roleId,
- locked);
- },
- "xyz.openbmc_project.User.Manager",
- "/xyz/openbmc_project/user",
- "xyz.openbmc_project.User.Manager", "RenameUser", username,
- *newUserName);
- });
+ std::bind_front(handleAccountPatch, std::ref(app)));
BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/<str>/")
.privileges(redfish::privileges::deleteManagerAccount)
.methods(boost::beast::http::verb::delete_)(
- [&app](const crow::Request& req,
- const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
- const std::string& username) -> void {
- if (!redfish::setUpRedfishRoute(app, req, asyncResp))
- {
- return;
- }
-
-#ifdef BMCWEB_INSECURE_DISABLE_AUTHX
- // If authentication is disabled, there are no user accounts
- messages::resourceNotFound(
- asyncResp->res, "#ManagerAccount.v1_4_0.ManagerAccount",
- username);
- return;
-
-#endif // BMCWEB_INSECURE_DISABLE_AUTHX
- sdbusplus::message::object_path tempObjPath(rootUserDbusPath);
- tempObjPath /= username;
- const std::string userPath(tempObjPath);
-
- crow::connections::systemBus->async_method_call(
- [asyncResp, username](const boost::system::error_code ec) {
- if (ec)
- {
- messages::resourceNotFound(
- asyncResp->res, "#ManagerAccount.v1_4_0.ManagerAccount",
- username);
- return;
- }
-
- messages::accountRemoved(asyncResp->res);
- },
- "xyz.openbmc_project.User.Manager", userPath,
- "xyz.openbmc_project.Object.Delete", "Delete");
- });
+ std::bind_front(handleAccounttDelete, std::ref(app)));
}
} // namespace redfish