tju-yxq opened a new issue, #5249:
URL: https://github.com/apache/rocketmq-dashboard/issues/5249
## Problem
Studio administrators can create user accounts and disable them, but they
can never actually remove one. When a contractor's engagement ends, when a
shared account is replaced by individual accounts, or when an account was
simply created with a typo in the username, the row stays in the users table
forever. The user management page keeps listing it, CSV exports keep including
it, and — worse — the username stays permanently reserved: `createUser` rejects
any name that already exists with a 409, regardless of whether the old account
is enabled or disabled. A returning employee who should get their old username
back cannot, because the account that holds it cannot be deleted through the
console at all.
## Current behavior and reproduction
1. Sign in as an administrator and open **User Management**.
2. Create a user, for example `contractor-a`, for someone who will leave the
team at the end of the engagement.
3. When they leave, disable the account: the status switch turns it off and
revokes its sessions — but the row remains in the table, in every export, and
in the username namespace.
4. Look for a delete action in the row: the actions column only offers the
sessions drawer, the status switch, a password reset and session revocation.
There is no way to remove the account.
5. Later, try to recreate `contractor-a` for a returning colleague: the
create dialog fails with "Username is already in use" — the name is burned
until someone edits the database directly.
`server/src/main/java/org/apache/rocketmq/studio/auth/StudioUserController.java`
(around lines 52-97) exposes exactly these endpoints — `GET
/api/studio-users`, `POST /api/studio-users`, `POST /{userId}/status`, `POST
/{userId}/password`, `GET /{userId}/sessions`, `POST /{userId}/sessions/revoke`
— there is no delete mapping anywhere in the controller:
```java
@PostMapping("/{userId}/status")
public Result<RmqStudioUser> setUserEnabled(...) { ... }
```
And `AuthService.createUser` (around line 298) blocks reuse of the name no
matter what state the old account is in:
```java
if (findUserByUsername(username).isPresent()) {
throw new BusinessException(409, "Username is already in use");
}
```
`findUserByUsername` (around line 523) matches on the username column alone,
so a disabled or retired account reserves the name just as strongly as an
active one.
## Proposed behavior
- An administrator can delete a studio account from the user management
page, behind an explicit destructive confirmation.
- The delete removes the account row **and** its sessions in one transaction
— the sessions table has no foreign key, so orphaned token hashes would
otherwise linger as unreachable rows.
- The operator's own account cannot be deleted from the page (self-delete is
rejected with 400; disabling is the right tool there).
- The last enabled administrator cannot be deleted (409), under the same
`FOR UPDATE` row lock the disable path already uses, so two concurrent deletes
cannot strip a deployment of every admin.
- A **disabled** administrator can be deleted even when it is the only admin
account, because it is not part of the enabled-admin set that guards lockout.
- After deletion, the username becomes creatable again through the normal
create dialog.
- All existing endpoints and page behaviors stay unchanged.
## Acceptance criteria
- [ ] `DELETE /api/studio-users/{userId}` removes the account and returns
the standard ok envelope.
- [ ] The account's sessions are deleted in the same transaction (no
unreachable token rows remain).
- [ ] Deleting the currently authenticated account is rejected with 400 and
changes nothing.
- [ ] Deleting the last enabled administrator is rejected with 409 and
changes nothing.
- [ ] Deleting an administrator while another enabled administrator exists
succeeds.
- [ ] Deleting a disabled administrator (even the only one) succeeds.
- [ ] Deleting a missing user id is rejected with 404 "User not found".
- [ ] The page asks for an explicit confirmation before deleting and reloads
the list afterwards.
- [ ] The delete action is disabled for the operator's own row.
- [ ] After deletion, creating a user with the freed username succeeds.
## Importance
Must-have. Account offboarding is a normal lifecycle operation for any
multi-user console; today the account list grows monotonically and departed
usernames are reserved forever. The current workaround is to disable the
account and accept a permanently growing list plus a burned username, or to run
`DELETE FROM rmq_studio_user WHERE ...` directly against the database — which
bypasses session cleanup (the token rows survive and must be purged by hand or
by the expiry sweep) and carries real risk of fat-fingering a shared production
table.
## Duplicate check
Searched open and closed issues and PRs for `delete studio user`, `remove
user account`, `studio-users`, `user lifecycle`, and `delete user` (PRs). The
only adjacent items are #3206 (bounded batch **enable/disable** actions —
status toggling, not deletion) and two closed ACL-domain PRs (#2057, #2007 —
RocketMQ ACL users on instances, not Studio console accounts). Nothing covers
removing a Studio console account.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]