Skip to content

fix(auth): add timeout to prevent proxy auth requests from hanging#23105

Open
ipsitapp8 wants to merge 3 commits intogoharbor:mainfrom
ipsitapp8:fix-auth-timeout
Open

fix(auth): add timeout to prevent proxy auth requests from hanging#23105
ipsitapp8 wants to merge 3 commits intogoharbor:mainfrom
ipsitapp8:fix-auth-timeout

Conversation

@ipsitapp8
Copy link
Copy Markdown

Thank you for contributing to Harbor!

Fixes #23104

Summary
Fixes auth requests hanging indefinitely due to missing timeout.

What changed

  • Added a 30-minute timeout to HTTP clients in auth and bearer authorizers

Why
The HTTP clients were created without a timeout, so requests could hang indefinitely when upstream auth services stop responding.
Since these calls are inside a mutex-protected path, this can block other requests as well.

What I did NOT change

  • No config refactoring
  • No changes to registry client
  • No new abstractions

Validation

  • Ran: unit tests
  • Tested: simulated unresponsive upstream endpoint

Signed-off-by: ipsitapp8 <ipsitapp8@gmail.com>
@Vad1mo
Copy link
Copy Markdown
Member

Vad1mo commented Apr 14, 2026

This will not solve the problem. The timeout needs to be way lower. e.g. 30 seconds.

The reason is if there is a problem, the default 30 min will have the same effect as "unlimited" resulting in connections piling up, until Harbor becomes unresponsive or the system runs out of file descriptors.

@codecov
Copy link
Copy Markdown

codecov bot commented Apr 14, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 46.69%. Comparing base (1a236ce) to head (a726d63).
⚠️ Report is 1 commits behind head on main.

❗ There is a different number of reports uploaded between BASE (1a236ce) and HEAD (a726d63). Click for more details.

HEAD has 1 upload less than BASE
Flag BASE (1a236ce) HEAD (a726d63)
unittests 2 1
Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff             @@
##             main   #23105       +/-   ##
===========================================
- Coverage   66.04%   46.69%   -19.35%     
===========================================
  Files        1074      253      -821     
  Lines      116571    14326   -102245     
  Branches     2941     2941               
===========================================
- Hits        76987     6690    -70297     
+ Misses      35330     7279    -28051     
+ Partials     4254      357     -3897     
Flag Coverage Δ
unittests 46.69% <ø> (-19.35%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.
see 826 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR addresses Harbor proxy-cache hangs by ensuring auth-related HTTP requests (auth scheme probing and bearer token fetching) don’t wait indefinitely when an upstream registry/auth service becomes unresponsive.

Changes:

  • Add an http.Client.Timeout (30 minutes) to the registry auth scheme probing client.
  • Add an http.Client.Timeout (30 minutes) to the bearer token fetching client.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.

File Description
src/pkg/registry/auth/authorizer.go Adds a request timeout to the client used for /v2/ challenge probing to avoid indefinite hangs.
src/pkg/registry/auth/bearer/authorizer.go Adds a request timeout to the client used for bearer token retrieval to avoid indefinite hangs.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 51 to 54
client: &http.Client{
Transport: transport,
Timeout: 30 * time.Minute, // prevent hanging auth requests if upstream is unresponsive
},
Copy link

Copilot AI Apr 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The timeout is hardcoded to 30 minutes here, but the registry client timeout is already configurable via REGISTRY_HTTP_CLIENT_TIMEOUT. With the current change, operators who tune REGISTRY_HTTP_CLIENT_TIMEOUT will still see auth scheme probing/token requests use a fixed 30m, which is inconsistent and can be surprising operationally. Consider reusing the same env-driven value (or a shared helper/constant) instead of duplicating the literal 30*time.Minute.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider reusing the same env-driven value (or a shared helper/constant) instead of duplicating the literal 30*time.Minute.

30 minutes is a very high limit - better than nothing, but it would be great to have the ability to lower it (make it configurable). However, REGISTRY_HTTP_CLIENT_TIMEOUT may not be a good choice: auth requests are generally light and fast, while downloading binaries can take much more time. I have no good ideas for a name for the new option, though. 😕

Comment on lines 48 to 55
return &authorizer{
username: username,
password: password,
client: &http.Client{
Transport: transport,
Timeout: 30 * time.Minute, // prevent hanging auth requests if upstream is unresponsive
},
}
Copy link

Copilot AI Apr 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a unit test asserting NewAuthorizer sets a non-zero client timeout (ideally the same value as the configured registry HTTP client timeout). This guards against regressions back to an unbounded http.Client and makes the hanging-request fix verifiable in CI.

Copilot uses AI. Check for mistakes.
Comment on lines +44 to +47
authorizer.client = &http.Client{
Transport: transport,
Timeout: 30 * time.Minute, // prevent hanging auth requests if upstream is unresponsive
}
Copy link

Copilot AI Apr 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as in auth/authorizer.go: this hardcodes 30 minutes and bypasses the existing REGISTRY_HTTP_CLIENT_TIMEOUT setting used by the main registry client. To keep behavior consistent and configurable, consider sourcing the timeout from the same env-driven value (or a shared helper) rather than duplicating 30*time.Minute here.

Copilot uses AI. Check for mistakes.
Comment on lines 34 to 48
// NewAuthorizer return a bearer token authorizer
// The parameter "a" is an authorizer used to fetch the token
func NewAuthorizer(realm, service string, a lib.Authorizer, transport http.RoundTripper) lib.Authorizer {
authorizer := &authorizer{
realm: realm,
service: service,
authorizer: a,
cache: newCache(cacheCapacity),
}

authorizer.client = &http.Client{Transport: transport}
authorizer.client = &http.Client{
Transport: transport,
Timeout: 30 * time.Minute, // prevent hanging auth requests if upstream is unresponsive
}
return authorizer
Copy link

Copilot AI Apr 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add/extend unit tests to assert the bearer authorizer's underlying http.Client has a timeout set by NewAuthorizer. Since this package already has tests, a simple assertion via type-asserting to *authorizer would prevent future regressions to an infinite timeout.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Proxy cache: no HTTP timeout on upstream auth/token requests

7 participants