Skip to content

[feat][client] oauth2 trustcerts file and timeouts#24944

Merged
lhotari merged 15 commits into
apache:masterfrom
gulecroc:feat/oauth2-truststore
Nov 11, 2025
Merged

[feat][client] oauth2 trustcerts file and timeouts#24944
lhotari merged 15 commits into
apache:masterfrom
gulecroc:feat/oauth2-truststore

Conversation

@gulecroc

@gulecroc gulecroc commented Nov 4, 2025

Copy link
Copy Markdown
Contributor

Fixes #24437

Motivation

For client oauth2 authentication, allow to configure :

  • connect timeout
  • read timeout
  • trust certs file

Modifications

Verifying this change

  • Make sure that the change passes the CI checks.

(Please pick either of the following options)

This change is a trivial rework / code cleanup without any test coverage.

(or)

This change is already covered by existing tests, such as (please describe tests).

(or)

This change added tests and can be verified as follows:

(example:)

  • Added integration tests for end-to-end deployment with large payloads (10MB)
  • Extended integration test for recovery after broker failure

Does this pull request potentially affect one of the following parts:

If the box was checked, please highlight the changes

  • Dependencies (add or upgrade a dependency)
  • The public API
  • The schema
  • The default values of configurations
  • The threading model
  • The binary protocol
  • The REST endpoints
  • The admin CLI options
  • The metrics
  • Anything that affects deployment

Documentation

  • doc
  • [] doc-required
  • doc-not-needed
  • doc-complete

Matching PR in forked repository

PR in forked repository:

@github-actions github-actions Bot added the doc-required Your PR changes impact docs and you will update later. label Nov 4, 2025
@gulecroc

gulecroc commented Nov 4, 2025

Copy link
Copy Markdown
Contributor Author

Doc : apache/pulsar-site#1052

@github-actions github-actions Bot added doc-complete Your PR changes impact docs and the related docs have been already added. and removed doc-required Your PR changes impact docs and you will update later. labels Nov 4, 2025

@lhotari lhotari left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Besides having an API for instantiating the Authentication instance, it is necessary to consider how the Authentication instance would be instantiated when parameters are passed in authParams (for example in client.conf).

You should also update

/**
* Constructs a {@link ClientCredentialsFlow} from configuration parameters.
* @param params
* @return
*/
public static ClientCredentialsFlow fromParameters(Map<String, String> params) {
URL issuerUrl = parseParameterUrl(params, CONFIG_PARAM_ISSUER_URL);
String privateKeyUrl = parseParameterString(params, CONFIG_PARAM_KEY_FILE);
// These are optional parameters, so we only perform a get
String scope = params.get(CONFIG_PARAM_SCOPE);
String audience = params.get(CONFIG_PARAM_AUDIENCE);
return ClientCredentialsFlow.builder()
.issuerUrl(issuerUrl)
.audience(audience)
.privateKey(privateKeyUrl)
.scope(scope)
.build();
}
so that
public void configure(String encodedAuthParamString) {
if (StringUtils.isBlank(encodedAuthParamString)) {
throw new IllegalArgumentException("No authentication parameters were provided");
}
Map<String, String> params;
try {
params = AuthenticationUtil.configureFromJsonString(encodedAuthParamString);
} catch (IOException e) {
throw new IllegalArgumentException("Malformed authentication parameters", e);
}
String type = params.getOrDefault(CONFIG_PARAM_TYPE, TYPE_CLIENT_CREDENTIALS);
switch(type) {
case TYPE_CLIENT_CREDENTIALS:
this.flow = ClientCredentialsFlow.fromParameters(params);
break;
default:
throw new IllegalArgumentException("Unsupported authentication type: " + type);
}
}
would work.

@lhotari lhotari left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM

@lhotari lhotari added this to the 4.2.0 milestone Nov 5, 2025
@lhotari
lhotari requested a review from Copilot November 5, 2025 20:24

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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 refactors the OAuth2 authentication implementation to centralize HTTP client management and configuration. The main goal is to improve consistency by having the HTTP client created and configured in one place (FlowBase) and shared across components.

Key changes:

  • Centralized HTTP client creation in FlowBase with configurable timeouts and SSL trust certificates
  • Removed HTTP client instantiation logic from TokenClient and DefaultMetadataResolver, making them accept the client as a constructor parameter
  • Added a builder pattern to AuthenticationFactoryOAuth2 for more flexible configuration
  • Added test coverage for the new builder pattern

Reviewed Changes

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

Show a summary per file
File Description
AuthenticationFactoryOAuth2Test.java New test file validating the builder pattern and factory method functionality
TokenClient.java Simplified to accept AsyncHttpClient as constructor parameter, removed client creation logic and constants
DefaultMetadataResolver.java Refactored to accept AsyncHttpClient as constructor parameter and use async HTTP instead of URLConnection
FlowBase.java Added HTTP client initialization with configurable timeouts and SSL, plus close() method
ClientCredentialsFlow.java Updated to pass new parameters to parent constructor and pass httpClient to components
AuthenticationFactoryOAuth2.java Added ClientCredentialsBuilder class for flexible configuration
Comments suppressed due to low confidence (2)

pulsar-client/src/main/java/org/apache/pulsar/client/impl/auth/oauth2/protocol/TokenClient.java:49

  • Potential NullPointerException if httpClient is null. Since the constructor now requires httpClient as a parameter and doesn't validate it, calling close() with a null httpClient will throw an NPE. Consider adding null check in constructor or in close() method.
    public void close() throws Exception {
        httpClient.close();

pulsar-client/src/main/java/org/apache/pulsar/client/impl/auth/oauth2/AuthenticationFactoryOAuth2.java:1

  • Potential NullPointerException if credentialsUrl is null. The build() method calls credentialsUrl.toExternalForm() without validating that credentialsUrl is not null. Consider adding validation for required fields (issuerUrl and credentialsUrl) in the build() method.
/*

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

gulecroc and others added 3 commits November 6, 2025 07:51
…/oauth2/FlowBase.java

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@gulecroc

gulecroc commented Nov 6, 2025

Copy link
Copy Markdown
Contributor Author

I fix Copilot review

@lhotari

lhotari commented Nov 6, 2025

Copy link
Copy Markdown
Member

@gulecroc for future PRs, you might want to use "Personal CI" to run Pulsar CI in your own fork to get early CI feedback when working on a larger PR like this one. The benefit is that you have full control over the CI and wouldn't have to wait for one of the project maintainers to approve a CI run.

Regarding flaky tests, in apache/pulsar CI, there is a way for anyone to trigger a retry run. That happens by adding "/pulsarbot rerun-failure-checks" comment on the PR. We have a lot of flaky tests and retrying 1 to 3 times for a PR is common. Retrying can only be requested after all jobs in the workflow have completed.

@codecov-commenter

codecov-commenter commented Nov 6, 2025

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 75.60976% with 30 lines in your changes missing coverage. Please review.
✅ Project coverage is 74.32%. Comparing base (0896c0a) to head (6a1dc71).
⚠️ Report is 4 commits behind head on master.

Files with missing lines Patch % Lines
...pache/pulsar/client/impl/auth/oauth2/FlowBase.java 70.27% 9 Missing and 2 partials ⚠️
...client/impl/auth/oauth2/ClientCredentialsFlow.java 77.14% 6 Missing and 2 partials ⚠️
.../client/impl/auth/oauth2/protocol/TokenClient.java 33.33% 6 Missing ⚠️
.../auth/oauth2/protocol/DefaultMetadataResolver.java 73.33% 4 Missing ⚠️
.../impl/auth/oauth2/AuthenticationFactoryOAuth2.java 96.29% 0 Missing and 1 partial ⚠️
Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff              @@
##             master   #24944      +/-   ##
============================================
- Coverage     74.44%   74.32%   -0.12%     
+ Complexity    34071    33528     -543     
============================================
  Files          1920     1920              
  Lines        150062   150108      +46     
  Branches      17404    17407       +3     
============================================
- Hits         111708   111569     -139     
- Misses        29495    29645     +150     
- Partials       8859     8894      +35     
Flag Coverage Δ
inttests 26.18% <0.00%> (-0.45%) ⬇️
systests 22.88% <0.00%> (-0.03%) ⬇️
unittests 73.86% <75.60%> (-0.10%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
.../impl/auth/oauth2/AuthenticationFactoryOAuth2.java 93.10% <96.29%> (+4.21%) ⬆️
.../auth/oauth2/protocol/DefaultMetadataResolver.java 71.42% <73.33%> (+11.42%) ⬆️
.../client/impl/auth/oauth2/protocol/TokenClient.java 74.28% <33.33%> (-10.50%) ⬇️
...client/impl/auth/oauth2/ClientCredentialsFlow.java 79.36% <77.14%> (+4.36%) ⬆️
...pache/pulsar/client/impl/auth/oauth2/FlowBase.java 67.27% <70.27%> (+0.60%) ⬆️

... and 88 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.

@gulecroc

gulecroc commented Nov 6, 2025

Copy link
Copy Markdown
Contributor Author

/pulsarbot rerun-failure-checks

1 similar comment
@gulecroc

gulecroc commented Nov 6, 2025

Copy link
Copy Markdown
Contributor Author

/pulsarbot rerun-failure-checks

@gulecroc

Copy link
Copy Markdown
Contributor Author

/pulsarbot rerun-failure-checks

@lhotari lhotari left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM

@lhotari
lhotari merged commit b789d82 into apache:master Nov 11, 2025
141 of 148 checks passed
@gulecroc

Copy link
Copy Markdown
Contributor Author

Thank you @lhotari !
Can I carry over these changes to version 4.0.x LTS?

@lhotari

lhotari commented Nov 12, 2025

Copy link
Copy Markdown
Member

Thank you @lhotari! Can I carry over these changes to version 4.0.x LTS?

@gulecroc Usually new features aren't immediately added to LTS versions to ensure that changes don't cause regressions.
New features can be added to an LTS release by starting a discussion on the dev mailing list. In most cases, it's better to have a PIP available for referencing the changes.

I'm just wondering whether this feature is completed by this PR. Is the intention to support updates for trustCertsFilePath? In that case, more changes would be needed to add support for trustCertsFilePath changes. I think that decoupling from AsyncHttpClient would be useful and instead having an internal abstraction that hides implementation details.

One detail to take into account is that there is PIP-337: SSL Factory Plugin to customize SSLContext/SSLEngine generation, which is expected to be used for SSLContext/SSLEngine instance creation. For consistency, that solution should be used. It's also possible that the PIP-337 solution might require some changes to support this new use case.

I think it would be useful to write a PIP document to capture the requirements and at least the high-level design. A PIP will also help when starting the community discussion and decision-making to include changes to 4.0.x LTS regarding this area.

This might help in creating a PIP: (how to create an LLM generated draft)

Btw. Regarding the AsyncHttpClient used in OAuth authentication, I'd also like it support PIP-234 changes so that the client doesn't create it's own set of threads, but has a way to reuse them from the PulsarClient / PulsarAdminClient. The solution for that is still missing. PIP-234 was planned a long time ago and it wasn't implemented until recently. The implementation is in PRs #24790, #24784 and #24893 and will be available in 4.1.2 version. More changes are needed so that there would be an interface to be used by authentication plugins for getting access to the shared resources.
For authentication plugins, one possibility would be that there would be a way to directly get a HTTP client with given configuration (such as trustCertsFilePath) that is sufficiently abstracted so that there's no need to couple to AsyncHttpClient in authentication plugin implementations.

@lhotari

lhotari commented Feb 6, 2026

Copy link
Copy Markdown
Member

It should be fine to include in 4.0.9/4.1.3.

lhotari pushed a commit that referenced this pull request Feb 6, 2026
lhotari pushed a commit that referenced this pull request Feb 6, 2026
hshankar31 pushed a commit to datastax/pulsar that referenced this pull request Feb 11, 2026
(cherry picked from commit b789d82)
(cherry picked from commit f8827bd)
hshankar31 pushed a commit to datastax/pulsar that referenced this pull request Feb 16, 2026
(cherry picked from commit b789d82)
(cherry picked from commit f8827bd)
priyanshu-ctds pushed a commit to datastax/pulsar that referenced this pull request Feb 18, 2026
…datastax 4 0 ds 16 feb (#589)

* [improve][broker] Ensure metadata session state visibility and improve Unstable observability for ServiceUnitStateChannelImpl (apache#25132)

(cherry picked from commit 2a29be0)
(cherry picked from commit 85dc758)

* [improve][broker] Upgrade bookkeeper to 4.17.3 (apache#25166)

(cherry picked from commit 45def39)
(cherry picked from commit 333110a)

* fix license and pom file

* [fix][ml] Fix NoSuchElementException in EntryCountEstimator caused by a race condition (apache#25177)

(cherry picked from commit 9b70ba3)
(cherry picked from commit 9261869)

* [fix][test] Bump org.assertj:assertj-core from 3.27.5 to 3.27.7 (apache#25186)

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
(cherry picked from commit ce4ebea)
(cherry picked from commit 2c3402e)

* [improve][misc] Upgrade snappy version to 1.1.10.8 (apache#25182)

(cherry picked from commit b15f53b)
(cherry picked from commit 304fea1)

* [fix][proxy] Close client connection immediately when credentials expire and forwardAuthorizationCredentials is disabled (apache#25179)

(cherry picked from commit 3348470)
(cherry picked from commit c06f8ba)

* [fix][client] ControlledClusterFailover avoid unnecessary reconnection. (apache#25178)

Co-authored-by: fengwenzhi <fengwenzhi.max@bigo.sg>
(cherry picked from commit f0ec07b)
(cherry picked from commit b41488d)

* [fix][sec] Bump org.apache.solr:solr-core from 9.8.0 to 9.10.1 in /pulsar-io/solr (apache#25175)

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
(cherry picked from commit a2f888a)
(cherry picked from commit b532068)

* [improve][pip] PIP-453: Improve the metadata store threading model (apache#25173)

(cherry picked from commit c51346f)
(cherry picked from commit d81d6b3)

* [improve][client]Reduce unnecessary getPartitionedTopicMetadata requests when using retry and DLQ topics. (apache#25172)

(cherry picked from commit 52a4d5e)
(cherry picked from commit 71a3994)

* [fix][misc] Allow JWT tokens in OpenID auth without nbf claim (apache#25197)

(cherry picked from commit d630394)
(cherry picked from commit 2760ee9)

* [fix][sec] Exclude org.lz4:lz4-java and standardize on at.yawk.lz4-java to remediate CVE-2025-12183 and CVE-2025-66566 (apache#25198)

(cherry picked from commit c07f2ad)
(cherry picked from commit 2ac6d03)

* fix checkstyle failure and license issues

* [fix] [test] Upgrade docker-java to 3.7.0 (apache#25209)

(cherry picked from commit 4add84c)
(cherry picked from commit 92b5d55)

* [fix][client] Fix race condition between isDuplicate() and flushAsync() method in PersistentAcknowledgmentsGroupingTracker due to incorrect use Netty Recycler (apache#25208)

(cherry picked from commit 5aab2f0)
(cherry picked from commit 2206949)

* [improve][monitor] Upgrade OpenTelemetry to 1.56.0, Otel instrumentation to 2.21.0 and Otel semconv to 1.37.0 (apache#24994)

(cherry picked from commit 53162ff)
(cherry picked from commit a1d5b6c)

* [improve][proxy] Add regression tests for package upload with 'Expect: 100-continue' (apache#25211)

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
(cherry picked from commit e8fedb1)
(cherry picked from commit 0947639)

* fix license issues

* [fix][test]Fix flaky ExtensibleLoadManagerImplTest_testGetMetrics (apache#25216)

(cherry picked from commit 257d42f)
(cherry picked from commit a8eac91)

* [fix][broker] Fix ManagedCursorImpl.asyncDelete() method may lose previous async mark delete properties in race condition (apache#25165)

(cherry picked from commit bea6f8a)
(cherry picked from commit 4332a44)

* [fix][broker]Fix ledgerHandle failed to read by using new BK API (apache#25199)

(cherry picked from commit 6d51f88)
(cherry picked from commit 1631fed)

* [fix][client] Fix producer synchronous retry handling in failPendingMessages method (apache#25207)

(cherry picked from commit 611efe4)
(cherry picked from commit 30ae8fb)

* [fix][broker] Prevent missed topic changes in topic watchers and schedule periodic refresh with patternAutoDiscoveryPeriod interval (apache#25188)

(cherry picked from commit 2e06cc0)
(cherry picked from commit ba2a230)

* fix for complilation error

* [feat][io] implement pip-297 for jdbc sinks (apache#25195)

(cherry picked from commit 6f4ac21)
(cherry picked from commit 998a4b1)

* [fix][broker] Fix httpProxyTimeout config (apache#25223)

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
(cherry picked from commit 2d6ef6f)
(cherry picked from commit 3b39c7b)

* [improve][broker] Add strictAuthMethod to require explicit authentication method (apache#25185)

Co-authored-by: Ómar K. Yasin <oyasin@apple.com>
(cherry picked from commit bae9173)
(cherry picked from commit 27e34f6)

* [feat][client] oauth2 trustcerts file and timeouts (apache#24944)

(cherry picked from commit b789d82)
(cherry picked from commit f8827bd)

* [improve][client] Make authorization server metadata path configurable in AuthenticationOAuth2 (apache#25052)

Co-authored-by: hoguni <hoguni@lycorp.co.jp>
(cherry picked from commit 3cb7a7b)
(cherry picked from commit 705a99d)

* Revert "[improve][broker] Add strictAuthMethod to require explicit authentication method (apache#25185)"

This reverts commit 531eb91.

* [improve][broker] Add idle timeout support for http (apache#25224)

(cherry picked from commit 63220ea)
(cherry picked from commit 144e064)

* [fix][broker] Fix incomplete futures in topic property update/delete methods (apache#25228)

(cherry picked from commit c2ae180)
(cherry picked from commit ab05ca2)

* [fix][test] Fix Mockito stubbing race in TopicListServiceTest (apache#25227)

(cherry picked from commit c93dd7a)
(cherry picked from commit 38a126b)

* [improve][broker] Give the detail error msg when authenticate failed with AuthenticationException (apache#25221)

(cherry picked from commit 0a0ce6d)
(cherry picked from commit 2a46c70)

* [fix][client] Send all chunkMessageIds to broker for redelivery (apache#25229)

(cherry picked from commit 0a0ce6d)
(cherry picked from commit f49c7b2)

* [fix][broker] Fix transactionMetadataFuture completeExceptionally with null value (apache#25231)

Co-authored-by: 张浩 <zhanghao60@100.me>
(cherry picked from commit 0e5d424)
(cherry picked from commit 42283f4)

* uncomment distribution management in pom

* Reapply "[improve][meta] PIP-453: Improve the metadata store threading model (apache#25187)"

This reverts commit a6aab86.

(cherry picked from commit 4f9b2ca)

* [improve] Upgrade Netty to 4.1.131.Final (apache#25232)

(cherry picked from commit db91b93)
(cherry picked from commit a6c602a)

* [fix][test] fix testBatchMetadataStoreMetrics. (apache#25241)

(cherry picked from commit 9db31cc)
(cherry picked from commit abbd478)

* [fix][test] Fix ResourceQuotaCalculatorImplTest#testNeedToReportLocalUsage (apache#25247)

(cherry picked from commit 48774de)
(cherry picked from commit 9343837)

* [fix][meta] Metadata cache refresh might not take effect (apache#25246)

(cherry picked from commit 24eba10)
(cherry picked from commit 6d81292)

* fix pulsar-proxy unit test case failure

* fix safe delete URLRegexLookupProxyHandler which is not used

* Revert "fix safe delete URLRegexLookupProxyHandler which is not used"

This reverts commit 158fc14.

* Revert "fix pulsar-proxy unit test case failure"

This reverts commit 4efcf70.

* updated hardcoded newLookupProxyHandler in ProxyService for failing URLRegexLookupProxyHandlerTest

* Revert "[improve][monitor] Upgrade OpenTelemetry to 1.56.0, Otel instrumentation to 2.21.0 and Otel semconv to 1.37.0 (apache#24994)"

This reverts commit 5e5328e

* reverted lincense for opentelemetry upgrade changes

* Revert "updated hardcoded newLookupProxyHandler in ProxyService for failing URLRegexLookupProxyHandlerTest"

This reverts commit a4f07dc.

* reverted mismatch commits changes in ProxyConnection.java

* fix code-style issue

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: Kai Wang <kwang@apache.org>
Co-authored-by: Yong Zhang <zhangyong1025.zy@gmail.com>
Co-authored-by: Lari Hotari <lhotari@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Zixuan Liu <nodeces@gmail.com>
Co-authored-by: Wenzhi Feng <thetumbled@apache.org>
Co-authored-by: fengwenzhi <fengwenzhi.max@bigo.sg>
Co-authored-by: Yunze Xu <xyzinfernity@163.com>
Co-authored-by: zhenJiangWang <zhenjiang427@gmail.com>
Co-authored-by: guptas6est <sanaya.gupta@est.tech>
Co-authored-by: Matteo Merli <mmerli@apache.org>
Co-authored-by: Oneby Wang <44369297+oneby-wang@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: fengyubiao <yubiao.feng@streamnative.io>
Co-authored-by: Malla Sandeep <sandeep.malla78@gmail.com>
Co-authored-by: Bäm <dev@sandchaschte.ch>
Co-authored-by: Omar Yasin <omarkj@icloud.com>
Co-authored-by: Ómar K. Yasin <oyasin@apple.com>
Co-authored-by: gulecroc <gu.lecroc@gmail.com>
Co-authored-by: Hideaki Oguni <22386882+izumo27@users.noreply.github.com>
Co-authored-by: hoguni <hoguni@lycorp.co.jp>
Co-authored-by: Cong Zhao <zhaocong@apache.org>
Co-authored-by: sinan liu <liusinan1998@gmail.com>
Co-authored-by: Jiwei Guo <technoboy@apache.org>
Co-authored-by: cai minjian <905767378@qq.com>
Co-authored-by: Hao Zhang <zhanghao1@cmss.chinamobile.com>
Co-authored-by: 张浩 <zhanghao60@100.me>
Co-authored-by: Lari Hotari <lhotari@apache.org>
Co-authored-by: zzb <48124861+zhaizhibo@users.noreply.github.com>
priyanshu-ctds pushed a commit to datastax/pulsar that referenced this pull request Feb 23, 2026
(cherry picked from commit b789d82)
(cherry picked from commit f8827bd)
lhotari added a commit to lhotari/pulsar that referenced this pull request Jul 4, 2026
…nto CLIENT_OAUTH2

Today FlowBase's hybrid discriminator sends an OAuth2 plugin's own IdP TLS
material (trustCertsFilePath / tlsCertFile / tlsKeyFile params, issue apache#24944) to
the deprecated legacy private AsyncHttpClient. Fold it instead so the framework
PulsarHttpClient serves IdP mTLS / custom trust on the new PIP-478 TLS path
(a stage-4c prerequisite: the deprecated fallback becomes unreachable when a TLS
factory exists, and is removed in 4c).

- FlowBase.idpTlsPolicy / AuthenticationOAuth2.idpTlsPolicy expose the flow's IdP
  TLS parameters as a CLIENT_OAUTH2 TlsPolicy (empty when the flow carries none).
- ClientTlsFactorySupport.composePolicies folds that policy into CLIENT_OAUTH2 —
  the single compose home for both the v5-builder tlsPolicy path and the v4 flip
  path, so no pulsar-client-v5 change is needed. It runs only when the client is
  already on the new TLS path, so a legacy / plain-v4 client is untouched (opt-in
  respected). FrameworkHttpClientFactory.configureTls already resolves the
  instance's tlsPurpose (CLIENT_OAUTH2), so the framework client now serves the
  folded IdP material; the FileBasedTlsFactory is immutable after construction, so
  the fold happens during client build, before the factory is built.
- FlowBase's discriminator narrows to "no TLS factory available at all": the
  framework client is used when a factory is present
  (FrameworkHttpClientFactory.hasTlsFactory()) even for a flow with its own IdP
  material; the deprecated private client stays only on the legacy path.

Gates: OAuth2IdpTlsFoldTest (fold parsing, 4/4); OAuth2IdpTlsFrameworkClientTest
(WireMock HTTPS + custom CA: the framework client trusts the IdP only because the
plugin's trustCertsFilePath was folded into CLIENT_OAUTH2 — without the fold the
same request is PKIX-rejected, 2/2; pulsar.test-certs-conventions added for the
shared CA certs). Full oauth2 suite + TokenOauth2AuthenticatedProducerConsumerTest
(2/2) + CredentialOffloadTest (3/3) unmodified green; SaslAuthenticateTest,
ClientCnxAsyncAuthTest, V5TlsProducerConsumerTest green (shared code touched).

Also appends the stage-4a entry (items 1/2/3) to the implementation log.

Assisted-by: Claude Code (Opus 4.8)
lhotari added a commit to lhotari/pulsar that referenced this pull request Jul 4, 2026
…nbound plugins

### Motivation

PIP-478 stage 4c (86a59df) removed the private OAuth2 `AsyncHttpClient` and
made `FlowBase.getHttpClient()` throw `IllegalStateException` whenever no
framework HTTP client factory was bound, on the assumption that
`AuthenticationOAuth2` only ever runs inside a `PulsarClient`/`PulsarAdmin`. That
assumption is false: the proxy (`ProxyServiceStarter`), the broker broker-client
and the CLI tools create the plugin directly via
`AuthenticationFactory.create(plugin, params).start()` and never bind a factory.
This regressed the proxy's OAuth2 broker-client auth — a real production breakage
of the `Authentication` public-API contract that has supported standalone
`start()` + `getAuthData()` for years — and deterministically failed
`ProxyTlsWithAuthTest > setup`.

### Modifications

- New package-private `StandaloneOAuth2HttpClientFactory` wraps a
  `FrameworkHttpClientFactory` with null event-loop/timer/resolver suppliers
  (HTTP-only; AsyncHttpClient self-provisions, mirroring the admin OAuth2 binding)
  and, only when the flow carries its own IdP TLS material, a standalone
  `FileBasedTlsFactory` serving it on `CLIENT_OAUTH2` with rotation (its own
  single-thread scheduler). With no IdP material the framework client uses the
  platform default trust store, matching v4 behaviour. All owned resources are
  released by `close()`.
- `FlowBase.getHttpClient()` no longer throws; a new `resolveHttpClientFactory()`
  returns the bound framework factory when present, else lazily builds and owns
  the standalone one, closed in `FlowBase.close()`. This restores the pre-4c
  standalone capability (incl. issue apache#24944 IdP trust/mTLS) on the new SPI without
  any change to the proxy/broker/CLI call sites or the failing test.
- New `StandaloneOAuth2HttpClientFactoryTest` (WireMock IdP): plain-HTTP IdP,
  test-CA HTTPS IdP trusted via the flow's `trustCertsFilePath`, and HTTPS IdP
  rejected without it.

Assisted-by: Claude Code (Opus 4.8)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cherry-picked/branch-4.0 cherry-picked/branch-4.1 doc-complete Your PR changes impact docs and the related docs have been already added. release/4.0.9 release/4.1.3

Projects

None yet

Development

Successfully merging this pull request may close these issues.

OAuth2 client auth PEM truststore

4 participants