Skip to content

Fix OkHttp client mTLS when using the platform default trust store#8565

Open
Debashismitra01 wants to merge 8 commits into
open-telemetry:mainfrom
Debashismitra01:fix/okhttp-client-mtls-default-trust
Open

Fix OkHttp client mTLS when using the platform default trust store#8565
Debashismitra01 wants to merge 8 commits into
open-telemetry:mainfrom
Debashismitra01:fix/okhttp-client-mtls-default-trust

Conversation

@Debashismitra01

Copy link
Copy Markdown
Contributor

Summary

This PR fixes an inconsistency between the OkHttp and JDK OTLP HTTP senders when client mTLS is configured without custom trusted certificates.

Previously, when only setClientTls(...) (or the equivalent autoconfigure properties) was configured, TlsConfigHelper correctly created an SSLContext containing the client KeyManager, but the OkHttp sender skipped installing the custom SSLSocketFactory because no explicit X509TrustManager was provided. As a result, OkHttp fell back to the platform default SSLSocketFactory, causing the configured client certificate to be silently omitted during the TLS handshake.

This change resolves the platform default X509TrustManager when no custom trust manager is configured and uses it when installing the custom SSLSocketFactory, making the OkHttp sender behave consistently with the JDK sender.

Changes

  • Add a helper for resolving the platform default X509TrustManager.
  • Use the platform default trust manager when configuring the OkHttp HTTP sender if no custom trust manager is supplied.
  • Add a regression test covering client mTLS without custom trusted certificates against an mTLS-required endpoint.

Fixes #8562

@Debashismitra01 Debashismitra01 requested a review from a team as a code owner July 3, 2026 00:58
@linux-foundation-easycla

linux-foundation-easycla Bot commented Jul 3, 2026

Copy link
Copy Markdown

CLA Signed
The committers listed above are authorized under a signed CLA.

@Debashismitra01 Debashismitra01 force-pushed the fix/okhttp-client-mtls-default-trust branch 2 times, most recently from 76a1e10 to 1f4e437 Compare July 3, 2026 02:01
@codecov

codecov Bot commented Jul 3, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 95.45455% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 91.62%. Comparing base (2724fc6) to head (539d1a9).

Files with missing lines Patch % Lines
...va/io/opentelemetry/exporter/internal/TlsUtil.java 88.88% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff            @@
##               main    #8565   +/-   ##
=========================================
  Coverage     91.61%   91.62%           
- Complexity    10311    10315    +4     
=========================================
  Files          1013     1013           
  Lines         27260    27278   +18     
  Branches       3201     3202    +1     
=========================================
+ Hits          24975    24994   +19     
+ Misses         1560     1558    -2     
- Partials        725      726    +1     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@Debashismitra01

Copy link
Copy Markdown
Contributor Author

Hi! I ran into an issue with the patch coverage check. The remaining uncovered lines are primarily defensive exception paths introduced by the new default trust manager resolution (e.g. TlsUtil.defaultTrustManager() failure handling). These paths are difficult to exercise without introducing static mocking of JDK/Mockito internals.

I considered refactoring the implementation to reduce the uncovered branches, but that would either reintroduce the original bug or require resolving the default trust manager multiple times, which I'd prefer to avoid. Before I proceed further, could you advise on the preferred direction?

Should I add tests using static mocking for these exception paths?
Or would you prefer a different implementation that keeps the fix simpler while preserving the intended behavior?

I'd appreciate your guidance on which approach best fits the project's expectations.

@Debashismitra01 Debashismitra01 force-pushed the fix/okhttp-client-mtls-default-trust branch from 09b53c2 to b6f5f6b Compare July 6, 2026 02:21
@abdessattar23

Copy link
Copy Markdown
Contributor

Hey Mitra, thanks for taking care of this just couple things. The default trust manager gets resolved twice (once in getSslContext(), once in the sender), any way to do it once? And is the getSslContext() change needed? init(..., null, ...) already falls back to the platform default TMs.
Otherwise LGTM

Comment thread CHANGELOG.md Outdated
@Debashismitra01 Debashismitra01 force-pushed the fix/okhttp-client-mtls-default-trust branch 2 times, most recently from 103d4b8 to 1a24c95 Compare July 6, 2026 19:23
@opentelemetry-pr-dashboard

Copy link
Copy Markdown

This PR has review comments. Review suggestions, whether from maintainers or automated reviewers, aren't always correct or required. Please evaluate each comment on its merits, then make sure each thread has a clear outcome.

For example, link to the commit if you applied a suggestion, explain why it wasn't applied, or ask a follow-up question.

Automation flags a PR for human review once every review thread has a reply or is marked as resolved.

Status across open PRs is visible on the pull request dashboard.

Comment thread CHANGELOG.md Outdated
@Debashismitra01 Debashismitra01 force-pushed the fix/okhttp-client-mtls-default-trust branch from 1a24c95 to 2befe38 Compare July 6, 2026 20:46
@psx95

psx95 commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Should I add tests using static mocking for these exception paths? Or would you prefer a different implementation that keeps the fix simpler while preserving the intended behavior?

I could not find any instances where static mocking is used in the repo, so I think we want to avoid that even though the mocking section did not explicitly mention it.

I think you could follow a pattern similar to how keyManager is being tested using a method added explicitly to facilitate testing.

 // Visible for testing
  static X509TrustManager defaultTrustManager(TrustManagerFactory tmf) throws SSLException {
   ...
  }

You could then refactor your existing method:

 public static X509TrustManager defaultTrustManager() throws SSLException {
    try {
      TrustManagerFactory tmf =
          TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
      return defaultTrustManager(tmf); //  <-- the visible for testing method 
    } catch (NoSuchAlgorithmException e) {
      throw new SSLException("Could not build default TrustManager.", e);
    }
  }

Hopefully this should increase coverage by allowing you to pass mocked TrustManagerFactory objects so you can control getTrustManagers and init methods (I can't seem to see exactly which lines are uncovered).

@Debashismitra01

Copy link
Copy Markdown
Contributor Author

Should I add tests using static mocking for these exception paths? Or would you prefer a different implementation that keeps the fix simpler while preserving the intended behavior?

I could not find any instances where static mocking is used in the repo, so I think we want to avoid that even though the mocking section did not explicitly mention it.

I think you could follow a pattern similar to how keyManager is being tested using a method added explicitly to facilitate testing.

 // Visible for testing
  static X509TrustManager defaultTrustManager(TrustManagerFactory tmf) throws SSLException {
   ...
  }

You could then refactor your existing method:

 public static X509TrustManager defaultTrustManager() throws SSLException {
    try {
      TrustManagerFactory tmf =
          TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
      return defaultTrustManager(tmf); //  <-- the visible for testing method 
    } catch (NoSuchAlgorithmException e) {
      throw new SSLException("Could not build default TrustManager.", e);
    }
  }

Hopefully this should increase coverage by allowing you to pass mocked TrustManagerFactory objects so you can control getTrustManagers and init methods (I can't seem to see exactly which lines are uncovered).

Thanks for the suggestion! I was able to get the patch coverage above the required threshold without introducing static mocking. I kept the current approach and avoided adding extra testing hooks since coverage is now passing.

@psx95 psx95 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.

Thanks for following up on the review! Some final thoughts/comments on the PR.

Comment thread exporters/common/src/main/java/io/opentelemetry/exporter/internal/TlsUtil.java Outdated
Comment thread CHANGELOG.md Outdated
@Debashismitra01 Debashismitra01 force-pushed the fix/okhttp-client-mtls-default-trust branch 3 times, most recently from 02bcf5f to e99a75d Compare July 7, 2026 19:27
@Debashismitra01

Copy link
Copy Markdown
Contributor Author

Thanks for the review! I addressed the remaining comments:

  • Updated the default trust manager tests to avoid static mocking/global property changes and follow the existing test helper pattern.
  • Applied the requested cleanup changes.
    All checks are passing now.

Thanks again for the feedback!

@Debashismitra01 Debashismitra01 force-pushed the fix/okhttp-client-mtls-default-trust branch from e99a75d to c7e07ce Compare July 10, 2026 07:56
@Debashismitra01

Copy link
Copy Markdown
Contributor Author

Thanks, updated defaultTrustManager_returnsX509TrustManager to use the real default trust manager instead of mocking since that covers the intent better. I kept the helper-based approach for the failure case to avoid suppressing CannotMockMethod and stay consistent with the existing test patterns.

@otelbot otelbot Bot added the api-change Changes to public API surface area label Jul 11, 2026
@Debashismitra01 Debashismitra01 force-pushed the fix/okhttp-client-mtls-default-trust branch from 121855c to 22732c7 Compare July 11, 2026 02:10
@otelbot otelbot Bot removed the api-change Changes to public API surface area label Jul 11, 2026
@Debashismitra01 Debashismitra01 force-pushed the fix/okhttp-client-mtls-default-trust branch from 22732c7 to e9e1268 Compare July 11, 2026 04:53
@Debashismitra01 Debashismitra01 force-pushed the fix/okhttp-client-mtls-default-trust branch from e9e1268 to 3d818fa Compare July 11, 2026 05:06
@otelbot otelbot Bot added the api-change Changes to public API surface area label Jul 11, 2026
@otelbot

otelbot Bot commented Jul 11, 2026

Copy link
Copy Markdown
Contributor

⚠️ API changes detected — additional maintainer review required

@jack-berg @jkwatson

This PR modifies the public API surface area of the following module(s):

  • opentelemetry-api
  • opentelemetry-common
  • opentelemetry-context
  • opentelemetry-exporter-common
  • opentelemetry-exporter-logging
  • opentelemetry-exporter-logging-otlp
  • opentelemetry-exporter-otlp
  • opentelemetry-exporter-otlp-common
  • opentelemetry-exporter-sender-grpc-managed-channel
  • opentelemetry-exporter-sender-jdk
  • opentelemetry-exporter-sender-okhttp
  • opentelemetry-exporter-zipkin
  • opentelemetry-extension-kotlin
  • opentelemetry-extension-trace-propagators
  • opentelemetry-opentracing-shim
  • opentelemetry-sdk
  • opentelemetry-sdk-common
  • opentelemetry-sdk-extension-autoconfigure
  • opentelemetry-sdk-extension-autoconfigure-spi
  • opentelemetry-sdk-extension-jaeger-remote-sampler
  • opentelemetry-sdk-logs
  • opentelemetry-sdk-metrics
  • opentelemetry-sdk-testing
  • opentelemetry-sdk-trace

Please review the changes in docs/apidiffs/current_vs_latest/ carefully before approving.

@Debashismitra01

Copy link
Copy Markdown
Contributor Author

Note: the last commit (Update apidiffs baseline to 1.64.0) is unrelated to this PR's functional changes — it's just regenerating docs/apidiffs/current_vs_latest/*.txt because a new OpenTelemetry release (1.64.0) shifted the comparison baseline from 1.63.0. No actual API surface changes from this PR's mTLS fix; happy to confirm if useful.

@Debashismitra01 Debashismitra01 requested a review from psx95 July 14, 2026 01:58
@psx95

psx95 commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Hi @Debashismitra01,
Perhaps you could try to rebase your commits onto the latest main once ? I think there should be no changes in the docs/apidiffs/current_vs_latest folder.

@Debashismitra01

Copy link
Copy Markdown
Contributor Author

I have tried doing rebase but still this changes wasn't fixed. One of my PR was merged that have the same issue. Maybe I can try again if it's fixed @psx95

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

api-change Changes to public API surface area

Projects

None yet

Development

Successfully merging this pull request may close these issues.

OTLP HTTP exporter (OkHttp sender) silently drops client mTLS certificate when no ca certificates are configured

3 participants