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