diff --git a/server/channels/api4/user.go b/server/channels/api4/user.go index ab2403b57a..861485781a 100644 --- a/server/channels/api4/user.go +++ b/server/channels/api4/user.go @@ -1676,6 +1676,13 @@ func updateUserActive(c *Context, w http.ResponseWriter, r *http.Request) { return } + if user.IsBot { + if permErr := c.App.SessionHasPermissionToManageBot(c.AppContext, *c.AppContext.Session(), c.Params.UserId); permErr != nil { + c.Err = permErr + return + } + } + if active && user.IsGuest() && !*c.App.Config().GuestAccountsSettings.Enable { c.Err = model.NewAppError("updateUserActive", "api.user.update_active.cannot_enable_guest_when_guest_feature_is_disabled.app_error", nil, "userId="+c.Params.UserId, http.StatusUnauthorized) return diff --git a/server/channels/api4/user_test.go b/server/channels/api4/user_test.go index 4702fc0572..cad6f10d88 100644 --- a/server/channels/api4/user_test.go +++ b/server/channels/api4/user_test.go @@ -2982,6 +2982,84 @@ func TestUpdateUserActive(t *testing.T) { CheckForbiddenStatus(t, resp) }) }) + + t.Run("user manager without bot permissions cannot deactivate bot accounts", func(t *testing.T) { + mainHelper.Parallel(t) + th := Setup(t).InitBasic() + + th.App.UpdateConfig(func(cfg *model.Config) { + *cfg.ServiceSettings.EnableBotAccountCreation = true + }) + + bot, botResp, err := th.SystemAdminClient.CreateBot(context.Background(), &model.Bot{ + Username: GenerateTestUsername(), + DisplayName: "Test Bot", + Description: "bot for permission test", + }) + require.NoError(t, err) + CheckCreatedStatus(t, botResp) + defer func() { + appErr := th.App.PermanentDeleteBot(th.Context, bot.UserId) + assert.Nil(t, appErr) + }() + + // Give BasicUser the User Manager permission to edit users, but no bot permissions. + th.AddPermissionToRole(model.PermissionSysconsoleWriteUserManagementUsers.Id, model.SystemUserRoleId) + defer th.RemovePermissionFromRole(model.PermissionSysconsoleWriteUserManagementUsers.Id, model.SystemUserRoleId) + + th.LoginBasic() + + // A User Manager without bot permissions must be blocked. + // Because the caller has neither PermissionReadOthersBots nor + // PermissionManageOthersBots, SessionHasPermissionToManageBot always + // returns 404 to avoid leaking the bot's existence. + resp, err := th.Client.UpdateUserActive(context.Background(), bot.UserId, false) + require.Error(t, err) + CheckNotFoundStatus(t, resp) + + // Confirm the bot is still active. + botUser, _, err := th.SystemAdminClient.GetUser(context.Background(), bot.UserId, "") + require.NoError(t, err) + require.Zero(t, botUser.DeleteAt, "bot should still be active") + }) + + t.Run("user with bot management permissions can deactivate bot accounts via user active endpoint", func(t *testing.T) { + mainHelper.Parallel(t) + th := Setup(t).InitBasic() + + th.App.UpdateConfig(func(cfg *model.Config) { + *cfg.ServiceSettings.EnableBotAccountCreation = true + }) + + bot, botResp, err := th.SystemAdminClient.CreateBot(context.Background(), &model.Bot{ + Username: GenerateTestUsername(), + DisplayName: "Test Bot", + Description: "bot for permission test", + }) + require.NoError(t, err) + CheckCreatedStatus(t, botResp) + defer func() { + appErr := th.App.PermanentDeleteBot(th.Context, bot.UserId) + assert.Nil(t, appErr) + }() + + // Assign both user-management and bot-management permissions to BasicUser. + th.AddPermissionToRole(model.PermissionSysconsoleWriteUserManagementUsers.Id, model.SystemUserRoleId) + defer th.RemovePermissionFromRole(model.PermissionSysconsoleWriteUserManagementUsers.Id, model.SystemUserRoleId) + th.AddPermissionToRole(model.PermissionManageOthersBots.Id, model.SystemUserRoleId) + defer th.RemovePermissionFromRole(model.PermissionManageOthersBots.Id, model.SystemUserRoleId) + + th.LoginBasic() + + // A user with ManageOthersBots should be allowed. + _, err = th.Client.UpdateUserActive(context.Background(), bot.UserId, false) + require.NoError(t, err) + + // Confirm the bot is now inactive. + botUser, _, err := th.SystemAdminClient.GetUser(context.Background(), bot.UserId, "") + require.NoError(t, err) + require.True(t, botUser.DeleteAt > 0, "bot should be inactive after deactivation") + }) } func TestGetUsers(t *testing.T) {