Cache auth result in SafeRequestStore to avoid double call

What does this MR do and why?

Cache auth result in SafeRequestStore to avoid double call

Contributes to https://gitlab.com/gitlab-com/gl-infra/production-engineering/-/work_items/28578

Problem

With throttle_authenticated_git_http enabled, Rack::Attack calls find_with_user_password (bcrypt 1) to identify the user for throttling, then GitHttpClientController calls it again (bcrypt 2) for authentication — doubling the cost per request.

Solution

Wrap the authenticator loop in find_with_user_password with Gitlab::SafeRequestStore.fetch so the second call within the same request returns the cached result. The cache key uses SHA256(password) (never stores plaintext). Side effects (user_auth_attempt!, logging) remain outside the cache and run on every call. SafeRequestStore is thread-local process memory cleared at end of request — not Redis or any persistent store. When RequestStore is inactive (e.g. background jobs), NullStore executes the block every time with no caching.

This also fixes the same double-bcrypt problem for throttle_authenticated_git_lfs.

References

https://gitlab.com/gitlab-com/gl-infra/production-engineering/-/work_items/28578+

Screenshots or screen recordings

Screenshot_2026-04-03_at_18.38.16

Screenshot_2026-04-03_at_18.38.54

Raw data
git clone http://gdk.test:3000/toolbox/gitlab-smoke-tests.git
## When Rate limiter is off

/toolbox/gitlab-smoke-tests.git/info/refs | 0.011373
/toolbox/gitlab-smoke-tests.git/info/refs | 0.414914
/toolbox/gitlab-smoke-tests.git/git-upload-pack | 0.41861
/toolbox/gitlab-smoke-tests.git/git-upload-pack | 0.40202
/toolbox/gitlab-smoke-tests.git/info/refs | 0.011216
/toolbox/gitlab-smoke-tests.git/info/refs | 0.396547
/toolbox/gitlab-smoke-tests.git/git-upload-pack | 0.553983
/toolbox/gitlab-smoke-tests.git/git-upload-pack | 0.390911
/toolbox/gitlab-smoke-tests.git/info/refs | 0.011555
/toolbox/gitlab-smoke-tests.git/info/refs | 0.392771
/toolbox/gitlab-smoke-tests.git/git-upload-pack | 0.414144
/toolbox/gitlab-smoke-tests.git/git-upload-pack | 0.391313
/toolbox/gitlab-smoke-tests.git/info/refs | 0.011197
/toolbox/gitlab-smoke-tests.git/info/refs | 0.396814
/toolbox/gitlab-smoke-tests.git/git-upload-pack | 0.399443
/toolbox/gitlab-smoke-tests.git/git-upload-pack | 0.407287
/toolbox/gitlab-smoke-tests.git/info/refs | 0.011259
/toolbox/gitlab-smoke-tests.git/info/refs | 0.388194
/toolbox/gitlab-smoke-tests.git/git-upload-pack | 0.392385
/toolbox/gitlab-smoke-tests.git/git-upload-pack | 0.394397

## When Rate limiter is on

### Before fix

/toolbox/gitlab-smoke-tests.git/info/refs | 0.053492
/toolbox/gitlab-smoke-tests.git/info/refs | 0.951372
/toolbox/gitlab-smoke-tests.git/git-upload-pack | 1.165686
/toolbox/gitlab-smoke-tests.git/git-upload-pack | 1.188724
/toolbox/gitlab-smoke-tests.git/info/refs | 0.011681
/toolbox/gitlab-smoke-tests.git/info/refs | 0.758207
/toolbox/gitlab-smoke-tests.git/git-upload-pack | 0.790359
/toolbox/gitlab-smoke-tests.git/git-upload-pack | 0.788036
/toolbox/gitlab-smoke-tests.git/info/refs | 0.012445
/toolbox/gitlab-smoke-tests.git/info/refs | 0.751753
/toolbox/gitlab-smoke-tests.git/git-upload-pack | 0.777891
/toolbox/gitlab-smoke-tests.git/git-upload-pack | 0.779285
/toolbox/gitlab-smoke-tests.git/info/refs | 0.020705
/toolbox/gitlab-smoke-tests.git/info/refs | 0.819522
/toolbox/gitlab-smoke-tests.git/git-upload-pack | 0.783056
/toolbox/gitlab-smoke-tests.git/git-upload-pack | 0.779211


### After fix

/toolbox/gitlab-smoke-tests.git/info/refs | 0.025602
/toolbox/gitlab-smoke-tests.git/info/refs | 0.457709
/toolbox/gitlab-smoke-tests.git/git-upload-pack | 0.473295
/toolbox/gitlab-smoke-tests.git/git-upload-pack | 0.486024
/toolbox/gitlab-smoke-tests.git/info/refs | 0.011363
/toolbox/gitlab-smoke-tests.git/info/refs | 0.430626
/toolbox/gitlab-smoke-tests.git/git-upload-pack | 0.706403
/toolbox/gitlab-smoke-tests.git/git-upload-pack | 0.429267
/toolbox/gitlab-smoke-tests.git/info/refs | 0.021732
/toolbox/gitlab-smoke-tests.git/info/refs | 0.427658
/toolbox/gitlab-smoke-tests.git/git-upload-pack | 0.432949
/toolbox/gitlab-smoke-tests.git/git-upload-pack | 0.439658
/toolbox/gitlab-smoke-tests.git/info/refs | 0.010926
/toolbox/gitlab-smoke-tests.git/info/refs | 0.418633
/toolbox/gitlab-smoke-tests.git/git-upload-pack | 0.427774
/toolbox/gitlab-smoke-tests.git/git-upload-pack | 0.431993
/toolbox/gitlab-smoke-tests.git/info/refs | 0.025345
/toolbox/gitlab-smoke-tests.git/info/refs | 0.419998
/toolbox/gitlab-smoke-tests.git/git-upload-pack | 0.438933
/toolbox/gitlab-smoke-tests.git/git-upload-pack | 0.423816

How to set up and validate locally

  1. Enable the throttle: in Admin > Settings > Network > Throttling, enable "Authenticated Git HTTP requests" with e.g. 5 requests per 60 seconds.
  2. Clone or fetch a repo repeatedly using HTTP Basic Auth with a password (not a PAT): git -c credential.helper='' clone http://user:password@localhost:3000/group/repo.git
  3. Observe that after 5 requests the server returns 429 Too Many Requests.
  4. To confirm bcrypt is no longer doubled, add a temporary log line in Gitlab::Auth.find_with_user_password and verify it appears only once per request in log/application.log.

MR acceptance checklist

Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.

Edited by Vasilii Iakliushin

Merge request reports

Loading