Repository navigation
Reset email background fallback - #53991
Conversation
95dc7b3 to
42cf2d8
Compare
Unreported flaky test detectedIf the flaky tests below are affected by the changes, please review and update the changes accordingly. Otherwise, a maintainer should report the flaky tests prior to merging the PR. org.keycloak.testsuite.oauth.ClientAuthSignedJWTTest#testUploadCertificatePemEcdsaKeycloak CI - FIPS IT (non-strict) org.keycloak.testsuite.oauth.ClientAuthSignedJWTTest#testUploadKeystoreBCFKSKeycloak CI - FIPS IT (non-strict) org.keycloak.testsuite.oauth.ClientAuthSignedJWTTest#testAssertionMissingIssuerKeycloak CI - FIPS IT (non-strict) org.keycloak.testsuite.oauth.ClientAuthSignedJWTTest#testWithClientAndMissingClientAssertionTypeKeycloak CI - FIPS IT (non-strict) org.keycloak.testsuite.oauth.ClientAuthSignedJWTTest#testMissingIssuerClaimKeycloak CI - FIPS IT (non-strict) org.keycloak.testsuite.oauth.ClientAuthSignedJWTTest#testAssertionExpiredKeycloak CI - FIPS IT (non-strict) org.keycloak.testsuite.oauth.ClientAuthSignedJWTTest#testCodeToTokenRequestSuccessRS256usingJwksKeycloak CI - FIPS IT (non-strict) org.keycloak.testsuite.oauth.ClientAuthSignedJWTTest#testCodeToTokenRequestSuccessPS384Keycloak CI - FIPS IT (non-strict) org.keycloak.testsuite.oauth.ClientAuthSignedJWTTest#testCodeToTokenRequestSuccessPS512Keycloak CI - FIPS IT (non-strict) org.keycloak.testsuite.oauth.ClientAuthSignedJWTTest#testECDSASignatureKeycloak CI - FIPS IT (non-strict) org.keycloak.testsuite.oauth.ClientAuthSignedJWTTest#testSuccessDefaultAlgWhenNoAlgSetInJWKKeycloak CI - FIPS IT (non-strict) org.keycloak.testsuite.oauth.ClientAuthSignedJWTTest#testAuthenticationFailsWhenClientSecretJWTAuthenticatorSetKeycloak CI - FIPS IT (non-strict) org.keycloak.testsuite.oauth.ClientAuthSignedJWTTest#testParEndpointAsAudienceKeycloak CI - FIPS IT (non-strict) org.keycloak.testsuite.oauth.ClientAuthSignedJWTTest#testInvalidClientAssertionTypeKeycloak CI - FIPS IT (non-strict) org.keycloak.testsuite.oauth.ClientAuthSignedJWTTest#testCodeToTokenRequestFailureRS256Keycloak CI - FIPS IT (non-strict) org.keycloak.testsuite.oauth.ClientAuthSignedJWTTest#testDirectGrantRequestSuccessKeycloak CI - FIPS IT (non-strict) org.keycloak.testsuite.oauth.ClientAuthSignedJWTTest#testUploadKeystorePKCS12Keycloak CI - FIPS IT (non-strict) org.keycloak.testsuite.oauth.ClientAuthSignedJWTTest#testMissingIssuedAtClaimKeycloak CI - FIPS IT (non-strict) org.keycloak.testsuite.oauth.ClientAuthSignedJWTTest#testSuccessWhenNoAlgSetInJWKKeycloak CI - FIPS IT (non-strict) org.keycloak.testsuite.oauth.ClientAuthSignedJWTTest#testMissingClientAssertionTypeKeycloak CI - FIPS IT (non-strict) org.keycloak.testsuite.oauth.ClientAuthSignedJWTTest#testMultipleAudiencesRejectedKeycloak CI - FIPS IT (non-strict) |
42cf2d8 to
e11f58a
Compare
There was a problem hiding this comment.
Thankd @gaoyikeshuer! I think we have no other way of doing this. But I don't like the idea os checking the threads and run normally if they are busy. I prefer to use normal ThreadPoolExecutor with a limited blocking queue (exception if queue is full). Just maintain unbounded for current types and set a default for the email (use a map or similar for the defaults, admins will be able to configure now min, max and queue size for the different types.
WDYT?
5e897ba to
9636e28
Compare
9636e28 to
d99fc80
Compare
d99fc80 to
a019183
Compare
There was a problem hiding this comment.
🔵 Needs a closer look
The security-sensitive reset-email changes require maintainer review of delivery policy and validation of response timing and delivery under delayed SMTP, concurrent resets, and queue saturation.
No open issues 🎉
1 resolved since last review
Review effort: Balanced
a019183 to
5ae89da
Compare
There was a problem hiding this comment.
🔵 Needs a closer look
The timing mitigation needs runtime validation beyond recording-executor unit tests to assess whether usernames remain distinguishable under realistic SMTP/database latency and executor saturation.
No open issues 🎉
Review effort: Balanced
There was a problem hiding this comment.
Thanks @gaoyikeshuer! Some final nit-picks, mainly for the test part. See if they make sense to you.
5ae89da to
03ad327
Compare
There was a problem hiding this comment.
🔵 Needs a closer look
Concurrent password-reset email delivery and transaction coordination require maintainer review and runtime validation under delayed SMTP and executor saturation to verify enumeration resistance, authentication availability, and commit/rollback behavior.
No open issues 🎉
Review effort: Balanced
Closes keycloak#26625 Signed-off-by: Yike Gao <yikegao8@gmail.com>
03ad327 to
9d0bf33
Compare
There was a problem hiding this comment.
Thanks for the changes @gaoyikeshuer!


Closes #26625.
the problem: when someone types a username on the fogot password page, KC answers "You should receive and email shortly" no matter what. but the response time it took to answer was not the same. for the existed username and has email. KC will build the email, connected to the mail server, and wait for the answer, only after then reply to the browser. for the non existed username, KC reply right away.
So the main fix idea is to stop waiting to the mail server. the page will answers first , adn the email is sent later by a small pool of backrgound threads (KC's exisiting ExecutorProvider, which has 4 threads by default)
now the KC will build email for the unknown users as well. so known and unknown usernames walk the same path.
background sending needs a limit or a flood of requests could pile up emails in memeory. in this pr the limit is simple at most one email per backgroudn thread. exactly like our current main branch no email got dropped.
the trade off of this PR is :
When all 4 background threads are busy, requests send the email themselves, so under heavy load the response waits for the mail server again, as it does today. Someone with a few valid accounts could keep the threads busy on purpose and then measure other usernames. This is never worse than today's behaviour, and the proper fix for load is rate limiting reset requests, which is a separate change. I'd like team to view on whether this is the right way and the alternatives are an unbounded queue, or dropping extra emails with an error event.
after the fix:
no matter known user or unknown user they got the reply same time
Screen.Recording.2026-10-15.at.13.41.08.mov
updated:
apply the fix for comments. now the form no longer waits for the mail server. The email is rendered during the request and delivered in the background by the existing ExecutorsProvider, using a new email executor.and only after the request’s transaction commits, so nothing is sent if the request rolls back.
Backpressure: the email executor has a bounded queue (4–64 threads, queue of 128 by default). When more than 64+128 emails are pending, the request fails wit 8000 h an EmailException and records SEND_RESET_PASSWORD_ERROR . emails never pile up in memory and there is no synchronous fallback. Admins can tune spi-executors--default--email-min/-max/-queue; the new queue option works for every executor type, and the existing types stay unbounded by default.