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]

Reply via email to