[Bug] OAuth2 authentication makes HTTP requests with no timeout, hanging the client indefinitely

Đang mở
#608 0 bình luận 0 reaction 0 người được giao Xem trên GitHub

Chưa có ai nhận issue này.

  • #609 của @david-streamlio — đã đóng, không merge

Đánh giá

Độ khó
3/5
Thời gian dự kiến
1-2 ngày
Mức phù hợp với người mới
78/100
Loại issue
Lỗi
Độ rõ ràng
Đặc tả rõ ràng
Mức độ hoạt động
Sôi nổi
Công nghệ
cpp
Lĩnh vực
authentication, networking

Hướng nghiên cứu

Bắt đầu với lib/CurlWrapper.h, đặc biệt là giá trị mặc định của options và thiết lập CURLOPT_TIMEOUT, sau đó kiểm tra fetchTokenEndpoint() và fetchOauth2Token() trong lib/auth/AuthOauth2.cc. So sánh cách xử lý timeout của chúng với lib/HTTPLookupService.cc và lib/auth/athenz/ZTSClient.cc, rồi chạy repro đính kèm với stub issuer. Hoàn tất khi các lệnh gọi HTTP OAuth2 trả về trong một timeout có giới hạn thay vì bị treo vô thời hạn.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Mô tả

Search before asking
  • I searched in the issues and found nothing similar.
Version

pulsar-client-cpp v4.2.0 (also verified at master, commit 1d08b2b, 2026-07-21)
Reproduced through pulsar-client (Python) 3.13.0 from PyPI, which pins pulsar-cpp 4.2.0
via dependencies.yaml.
OS: Linux x86_64

Minimal reproduce step

Requires no Pulsar broker and no real OAuth2 issuer. The script below starts a stub TCP
listener that accepts the connection and then never replies — the behaviour of a
black-holed or overloaded issuer.

pip install pulsar-client==3.13.0
python3 repro_oauth_timeout.py 100

Script attached. It configures the client with operation_timeout_seconds=5 and
connection_timeout_ms=5000, points issuer_url at the stub, and calls create_producer().

What did you expect to see?

The OAuth2 flow fails within a bounded, ideally configurable, period — and at minimum
within the client's own configured timeouts.

What did you see instead?

The call never returns. Observed output:

[*] pulsar-client 3.13.0
[*] operation_timeout_seconds=5, connection_timeout_ms=5000
[*] Calling create_producer(); watchdog set to 100s

    [stub:issuer] accepted TCP connection, now stalling (will never respond)
    still blocked after   15.0s (no client-side timeout has fired)
    still blocked after   30.0s (no client-side timeout has fired)
    still blocked after   45.0s (no client-side timeout has fired)
    still blocked after   60.0s (no client-side timeout has fired)
    still blocked after   75.0s (no client-side timeout has fired)
    still blocked after   90.0s (no client-side timeout has fired)
    still blocked after  105.0s (no client-side timeout has fired)

[RESULT] REPRODUCED. Still blocked in OAuth2 discovery after 105.0s.

Both configured client timeouts were exceeded by more than 20x with no sign of returning.
Neither operationTimeoutSeconds nor connectionTimeoutMs bounds the auth flow's HTTP calls.

Anything else?

Root cause: CurlWrapper::Options::timeoutInSeconds defaults to 0 (lib/CurlWrapper.h:55) and
is applied unconditionally at lib/CurlWrapper.h:123:

curl_easy_setopt(handle_, CURLOPT_TIMEOUT, options.timeoutInSeconds);

CURLOPT_TIMEOUT of 0 means no timeout in libcurl. CURLOPT_CONNECTTIMEOUT is never set
anywhere in the repository, leaving only libcurl's 300s default for the connect phase and
nothing at all once connected.

Both OAuth2 call sites leave the default in place:

  1. Issuer discovery — lib/auth/AuthOauth2.cc:277, in fetchTokenEndpoint(), passes a
    default-constructed options object:
    curl.get(wellKnownUrl, "Accept: application/json", {}, tlsContext);

  2. Token endpoint — lib/auth/AuthOauth2.cc:336-339, in fetchOauth2Token(), constructs
    options but sets only postFields.

This looks specific to the OAuth2 path. Other components set a timeout on the same wrapper:

  • lib/HTTPLookupService.cc:229 -> options.timeoutInSeconds = lookupTimeoutInSeconds_;
  • lib/auth/athenz/ZTSClient.cc:369 -> options.timeoutInSeconds = REQUEST_TIMEOUT;

Impact, as hit in production by a user running OAuth2 in Kubernetes: pods hang rather than
fail, so the problem stays invisible to health checks; and a transient issuer fault cannot
self-heal because recovery never starts.

Suggested fix: set a default timeout at both OAuth2 call sites following the existing
HTTPLookupService/ZTSClient pattern, and set CURLOPT_CONNECTTIMEOUT in CurlWrapper. Ideally
expose the value as an OAuth2 parameter.

repro_oauth_timeout.py

Are you willing to submit a PR?
  • I'm willing to submit a PR!
Ngôn ngữ chính
C++
Star
72
Fork
93
Chỉ số merge pull request
Không có pull request nào được merge trong 30 ngày

Chuẩn bị môi trường

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Issue khác của apache/pulsar-client-cpp

Tất cả issue của apache/pulsar-client-cpp

Issue tương tự

Thêm issue về C++

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.