yyqdbngt opened a new pull request, #5325:
URL: https://github.com/apache/rocketmq-dashboard/pull/5325

   ### Which Issue(s) This PR Fixes
   
   - Fixes #5303
   
   ### Brief Description
   
   A Studio session token stayed valid until its **absolute** expiry — 24 hours 
by default — no matter how long it went unused. The console already tracked and 
displayed inactivity: `last_seen_at` is written on authenticated requests, 
refreshed at most once per 5 minutes (`LAST_SEEN_UPDATE_INTERVAL`), classified 
as "长时间未活跃" after 15 minutes (`STALE_SESSION_THRESHOLD`) and reported as a 
stale-session count on the overview — but the token validation path in 
`AuthService` checked revocation and absolute expiry only, so a stale session 
stayed fully authenticated. A token copied from an abandoned browser or a 
shared workstation kept working for a day with zero activity required.
   
   This change adds an idle deadline:
   
   - `AuthProperties.sessionIdleTimeoutMinutes` 
(`studio.auth.session-idle-timeout-minutes`, env 
`STUDIO_AUTH_SESSION_IDLE_TIMEOUT_MINUTES`), default **30 minutes**, next to 
the other `studio.auth.*` deployment settings.
   - `AuthService.databaseUserForToken` rejects a session whose last use is 
older than the window **and** writes `revoked_at = now` on the row, so the 
session drawer and the overview counters stop counting a token nobody can use 
any more.
   - The existing five-minute `@Scheduled` session cleanup 
(`purgeExpiredSessions`) revokes idle-expired rows as well, so an abandoned 
token that is never presented again still disappears from the active-session 
views; rows are still deleted at absolute expiry exactly as before.
   - The in-memory (properties-based) mode tracks last-seen per token and 
enforces the same window, through token presentation and through its cleanup.
   - `0` is the explicit opt-out (absolute expiry only). Values 1–9 resolve to 
**10** minutes — deliberately above the 5-minute last-seen write throttle, so 
an active session's throttled writes can never lag enough to idle it out 
falsely. Values above 1440 fall back to the default, mirroring the absolute 
timeout's defensive clamp. Sessions written before `last_seen_at` existed 
(NULL) keep the absolute deadline as their only deadline. The absolute session 
timeout and the login flow are unchanged.
   
   The idle window is configured as a deployment property rather than as a 
field on the general-settings page: the enforcement, the opt-out and the 
scheduled revocation are this PR, and a settings-page field would ride on top 
of the same value.
   
   One existing assertion had to be narrowed for the new scheduled statement: 
`AuthServicePasswordChangeIntegrationTest` counted *every* 
`sessionMapper.update` call on its mocked mapper, and that same mapper is now 
also written once per sweep by `revokeIdleSessions`. Both verifications in that 
class now pin the statement they are actually about (`... contains("user_id")`) 
instead of counting all updates; no behavioural expectation changed.
   
   ### How Did You Test This Change?
   
   `AuthServiceIdleTimeoutTest` (new, mocks the session/user mappers and the 
settings repository, fixed clock at `2026-08-13T12:00:00Z`) asserts: a token 
unused for 60 minutes with an absolute expiry still in the future is rejected 
*and* its row is revoked; a token used 10 minutes ago stays authenticated and 
refreshes `last_seen_at`; a token inside the 5-minute write throttle is neither 
rewritten nor revoked; idle window 0 leaves a 6-hour-idle token authenticated; 
window 1 resolves to 10 minutes (7 minutes idle stays authenticated, 11 minutes 
is revoked); a session without `last_seen_at` keeps the absolute deadline; the 
scheduled cleanup revokes rows whose `last_seen_at` is older than 30 minutes 
with the same `revoked_at IS NULL AND expires_at > now` predicate the per-user 
revoke uses, and still deletes absolutely-expired rows; and both in-memory 
paths (presentation and cleanup) drop an idle token.
   
   ```powershell
   $ cd server && mvn -B -ntp test -Dtest=AuthServiceIdleTimeoutTest
   [ERROR] Tests run: 9, Failures: 6, Errors: 0, Skipped: 0   <- before the fix
   [INFO] Tests run: 9, Failures: 0, Errors: 0, Skipped: 0    <- after the fix
   [INFO] BUILD SUCCESS
   ```
   
   Raw red run (before the change):
   
   ```
   [ERROR] Tests run: 9, Failures: 6, Errors: 0, Skipped: 0, Time elapsed: 
2.579 s <<< FAILURE! -- in 
org.apache.rocketmq.studio.auth.AuthServiceIdleTimeoutTest
   Expecting value to be false but was true
   Expecting empty but was: 
{"studio-jwt-9bfe9449-e5fd-4fbb-821a-2002d80f9003"=AuthSession[user=LoginVO.UserInfo(userId=null,
 username=operator, admin=false), expiresAtMillis=1786708800000]}
   Wanted but not invoked:
   Expecting an empty Optional but was containing value: 
LoginVO.UserInfo(userId=1, username=operator, admin=false)
   [ERROR]   
AuthServiceIdleTimeoutTest.anIdleWindowBelowTheLastSeenThrottleResolvesToTheMinimumOfTenMinutes:122->configureIdleTimeoutMinutes:238
 AuthProperties has no session idle timeout setting
   [ERROR]   
AuthServiceIdleTimeoutTest.idleTimeoutZeroLeavesTheAbsoluteTimeoutAsTheOnlyDeadline:112->configureIdleTimeoutMinutes:238
 AuthProperties has no session idle timeout setting
   [ERROR]   
AuthServiceIdleTimeoutTest.inMemoryCleanupDropsTokensThatIdledOut:191
   Expecting empty but was: 
{"studio-jwt-9bfe9449-e5fd-4fbb-821a-2002d80f9003"=AuthSession[user=LoginVO.UserInfo(userId=null,
 username=operator, admin=false), expiresAtMillis=1786708800000]}
   [ERROR]   
AuthServiceIdleTimeoutTest.inMemorySessionsAlsoExpireOnceTheirTokenStaysIdle:176
   Expecting value to be false but was true
   [ERROR]   
AuthServiceIdleTimeoutTest.scheduledCleanupRevokesIdleSessionsAndStillDeletesAbsolutelyExpiredRows:154->theOnlySessionUpdate:222
   Wanted but not invoked:
   [ERROR]   
AuthServiceIdleTimeoutTest.tokenUnusedBeyondTheIdleWindowIsRejectedAndRevokedBeforeItsAbsoluteExpiry:85
   Expecting an empty Optional but was containing value: 
LoginVO.UserInfo(userId=1, username=operator, admin=false)
   [ERROR] Tests run: 9, Failures: 6, Errors: 0, Skipped: 0
   [INFO] BUILD FAILURE
   ```
   
   Green run after the change (same test file):
   
   ```powershell
   $ cd server && mvn -B -ntp test -Dtest=AuthServiceIdleTimeoutTest
   [INFO] You have 0 Checkstyle violations.
   [INFO] Tests run: 9, Failures: 0, Errors: 0, Skipped: 0
   [INFO] BUILD SUCCESS
   ```
   
   The full server suite was also run to check for regressions in the sessions 
that were already green:
   
   ```powershell
   $ cd server && mvn -B -ntp test
   [INFO] Tests run: 3331, Failures: 8, Errors: 27, Skipped: 4
   ```
   
   (3331 = the 3322 tests of the base revision plus the 9 new ones; the 8 
failures and 27 errors are the pre-existing MySQL-8 / external-CLI classes.)
   
   ### Checklist
   
   - [x] One coherent change; unrelated modifications are not bundled in
   - [x] Commit subject follows Conventional Commits
   - [x] Tests added or updated for non-trivial changes
   - [ ] New UI text has both Chinese and English entries under `web/src/i18n/` 
— does not apply, this change adds no UI text
   - [ ] Architecture constraints stay green — no ArchUnit rule class exists in 
the repository and this change adds none; the maven runs above report 0 
checkstyle violations
   - [x] New source files carry the ASF license header
   - [ ] Documentation touched where behaviour changed — not ticked: the new 
property is documented by the `AuthProperties` javadoc; 
`server/src/main/resources/application.yml` is outside the file set this change 
was scoped to, so no `studio.auth.session-idle-timeout-minutes` entry was added 
there
   


-- 
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