Repository navigation
Password reset: Report an unconfigured application URL before the user lookup and always apply the minimum response time - #24152
Conversation
…reset user lookup ApplicationUrlNotConfigured was only produced once the user had been found, so the reset endpoint answered a registered email differently from an unknown one on sites where the application URL could not be resolved. Add IForgotPasswordUriProvider.CanCreateForgotPasswordUriAsync for failures that don't depend on the user, and check it before the lookup. The default implementation succeeds, so existing providers are unaffected. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…dpoints The filter checked TimeSpan.Microseconds, which is only the 0-999 µs component of the remaining wait, so the delay was skipped whenever that component happened to be zero. Compare the whole TimeSpan instead, and measure with TimeProvider so the behaviour can be tested deterministically. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Claude finished @iOvergaard's task in 1m 39s —— View job PR ReviewTarget: This PR fixes two problems in the password reset endpoints. First, an unconfigured application URL now gets the same response whether or not the email belongs to a user: the new
Suggestions
Things I checked and found correct:
Approved with Suggestions for improvementGood to go, but please carefully consider the importance of the suggestions. |
AndyButland
left a comment
There was a problem hiding this comment.
Looks good @iOvergaard. Good catches and fixes to tighten this up.
|
…r lookup and always apply the minimum response time (#24152) Cherry-picked without the UserServiceCrudTests changes, which build on test helpers from #24042 (not in this release). The unit tests for both fixes are included. * fix(api): report an unconfigured application URL before the password reset user lookup ApplicationUrlNotConfigured was only produced once the user had been found, so the reset endpoint answered a registered email differently from an unknown one on sites where the application URL could not be resolved. Add IForgotPasswordUriProvider.CanCreateForgotPasswordUriAsync for failures that don't depend on the user, and check it before the lookup. The default implementation succeeds, so existing providers are unaffected. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(api): always apply the minimum response time on password reset endpoints The filter checked TimeSpan.Microseconds, which is only the 0-999 µs component of the remaining wait, so the delay was skipped whenever that component happened to be zero. Compare the whole TimeSpan instead, and measure with TimeProvider so the behaviour can be tested deterministically. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Added docs for EnsureMinimumResponseTimeFilter. --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: Andy Butland <abutland73@gmail.com>
…r lookup and always apply the minimum response time (#24152) Cherry-picked without the UserServiceCrudTests changes, which build on test helpers from #24042 (not in this release). The unit tests for both fixes are included. * fix(api): report an unconfigured application URL before the password reset user lookup ApplicationUrlNotConfigured was only produced once the user had been found, so the reset endpoint answered a registered email differently from an unknown one on sites where the application URL could not be resolved. Add IForgotPasswordUriProvider.CanCreateForgotPasswordUriAsync for failures that don't depend on the user, and check it before the lookup. The default implementation succeeds, so existing providers are unaffected. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(api): always apply the minimum response time on password reset endpoints The filter checked TimeSpan.Microseconds, which is only the 0-999 µs component of the remaining wait, so the delay was skipped whenever that component happened to be zero. Compare the whole TimeSpan instead, and measure with TimeProvider so the behaviour can be tested deterministically. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Added docs for EnsureMinimumResponseTimeFilter. --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: Andy Butland <abutland73@gmail.com>



Prerequisites
Description
Two small fixes to the backoffice password reset endpoints, both found while reviewing #24042.
1. Report an unconfigured application URL before looking up the user
POST /security/forgot-passwordreturns the same response whether or not the email belongs to a user, except for statuses that are determined before the lookup.ApplicationUrlNotConfiguredis surfaced on that basis, but it was only produced byIForgotPasswordUriProvider.CreateForgotPasswordUriAsync(user), after the user had been found. So on a site where the application URL can't be resolved, a registered email got a different response from an unknown one.IForgotPasswordUriProvidergetsCanCreateForgotPasswordUriAsync()for failures that don't depend on the user, andUserService.SendResetPasswordEmailAsyncchecks it before the lookup, the same way #24042 handlesPasswordResetUnavailable.ForgotPasswordUriProviderimplements it as the application URL check. The default implementation succeeds, so existing custom providers behave as before.2. Always apply the minimum response time
EnsureMinimumResponseTimeFilter(used by the request, verify and reset password endpoints) checkedforceWait.Microseconds > 0. That is only the 0-999 µs component of the remaining time, not the total, so the delay was skipped whenever that component happened to be zero. It now compares the wholeTimeSpan, and measures withTimeProviderinstead ofStopwatchso the behaviour can be tested.Testing
Automated:
UserServiceCrudTests.Reset_Password_Link_Unavailable_Status_Does_Not_Depend_On_Whether_User_Exists(registered and unknown email get the sameApplicationUrlNotConfiguredresult). Fails without the fix.EnsureMinimumResponseTimeFilterTests(delays until the minimum has elapsed, including a remaining wait of exactly 1.5 s; no delay once it has already elapsed). The 1.5 s case fails without the fix.UriProviderTests.CanCreateForgotPasswordUri_*for the provider's new check.Manual (optional):
Umbraco:CMS:WebRouting:UmbracoApplicationUrland detection disabled), with SMTP configured.🤖 Generated with Claude Code