feat(oauth2): support mTLS dynamic certificate rotation and 401 retry - #13986
Open
macastelaz wants to merge 22 commits into
Open
feat(oauth2): support mTLS dynamic certificate rotation and 401 retry#13986macastelaz wants to merge 22 commits into
macastelaz wants to merge 22 commits into
Conversation
Implementation of Phase 1-3 of the Cert-Bound Oauth2 Design Document: 1. Extend IdentityPoolCredentialSource to parse actorTokenFieldName. 2. Relax mutual exclusivity to allow BOTH file and certificate configurations. 3. Parse actor_token_type in ExternalAccountCredentials. 4. Refactor FileIdentityPoolTokenSupplier and track file timestamp via volatile CachedFile for the parsed JSON payload. 5. Inject actor_token and actor_token_type into StsTokenExchangeRequest using ActingParty. 6. Enforce that actor token extraction requires an mTLS STS configuration.
Fixes test failures and thread synchronization bugs regarding actor token credentials from https://paste.googleplex.com/5381957298028544
Contributor
There was a problem hiding this comment.
Code Review
This pull request introduces support for actor tokens and dynamic mTLS credential reloading within IdentityPoolCredentials. Key changes include the addition of an IdentityPoolActorTokenSupplier interface, the replacement of FileIdentityPoolSubjectTokenSupplier with a thread-safe, caching-enabled FileIdentityPoolTokenSupplier for both subject and actor tokens, and the implementation of a 401-retry mechanism that rebuilds the SSL context using a new DelegatingSSLSocketFactory in MtlsHttpTransportFactory. I have no feedback to provide as there are no review comments.
- Mark CachedFile and X509Provider transient to ensure clean serialization. - Add static modifier to FileIdentityPoolTokenSupplier serialVersionUID. - Make IdentityPoolActorTokenSupplier public with @NullMarked annotation. - Preserve actorTokenSupplier in IdentityPoolCredentials Builder copy constructor. - Mask actor_token in Slf4jLoggingHelpers sensitive keys. - Add no-arg constructor to MtlsHttpTransportFactory for serialization support. - Handle Data.isNull in FileIdentityPoolTokenSupplier JSON parsing. - Add comprehensive test coverage for supplier caching, builder, serialization, and log masking.
…uilder copy constructor - Guard actorTokenSupplier assignment with if (this.credentialSource == null) in Builder copy constructor. - Add getIdentityPoolActorTokenSupplier getter for test assertions. - Add createScoped tests for both file-sourced and supplier-sourced credentials with actor tokens.
…s and FileIdentityPoolTokenSupplier - Add builder_actorTokenTypeWithoutSupplier_throws testing missing supplier validation. - Add builder_fileWithCertificateConfig_initializesMtlsTransport testing mTLS initialization for composite file + cert sources. - Add toBuilder_preservesConfiguration testing builder reconstruction. - Add parseToken_textFormat_succeeds and parseToken_jsonFormat_missingFieldName_throws testing static token parsing methods.
… for STS token exchange Implementation of Phase 4 of the Cert-Bound OAuth2 Design Document (go/java-auth-cert-bound-oauth2): 1. Extend MtlsHttpTransportFactory to accept MtlsProvider (e.g. X509Provider) and implement rebuildContext() for dynamic KeyStore reloading when certificates are rotated on disk. 2. Implement DelegatingSSLSocketFactory in MtlsHttpTransportFactory so existing NetHttpTransport instances automatically delegate to the reloaded SSLSocketFactory. 3. Update IdentityPoolCredentials to initialize MtlsHttpTransportFactory with X509Provider instead of a static KeyStore. 4. Attach an HttpUnsuccessfulResponseHandler retry interceptor in ExternalAccountCredentials to detect 401 Unauthorized responses during mTLS STS token exchange, rebuild the SSL context, and retry once per refresh cycle. 5. Add unit tests in MtlsHttpTransportFactoryTest and ExternalAccountCredentialsTest.
…NetHttpTransport return type on MtlsHttpTransportFactory.create() Restores 100% binary bytecode compatibility for downstream Google Cloud client libraries (e.g. java-bigtable) while preserving dynamic SSL context rebuilding and STS 401 retry capabilities.
…o satisfy fmt-maven-plugin check
…dableTransportFactory
macastelaz
force-pushed
the
cert-bound-oauth-part3
branch
from
August 10, 2026 21:30
6a9fc02 to
cf818fb
Compare
…ontext rebuilding
… cert rotation and 401 retry loop
…ith static fixtures and SSLServerSocket
macastelaz
marked this pull request as ready for review
August 11, 2026 03:15
… non-mTLS actor token check
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
mTLS Dynamic Certificate Rotation & STS 401 Retry Loop
Note to Reviewers:
This PR is stacked on top of PR #13955 (
cert-bound-oauth-part2) and targets the upstreamoauth2-bound-tokensfeature branch.🔍 To review only the incremental Phase 4 diffs cleanly while #13955 is pending, see:
macastelaz/google-cloud-java: compare
cert-bound-oauth-part2...cert-bound-oauth-part3Overview
This PR implements the portion of the Cert-Bound OAuth2 Design Document (
go/java-auth-cert-bound-oauth2) which specifies the introduction of dynamic client certificate rotation for mutual TLS (mTLS) transports and an automatic401 Unauthorizedretry loop for Security Token Service (STS) token exchanges.Key Changes
Dynamic Certificate Rotation in
MtlsHttpTransportFactory(google-auth-library-oauth2-http):MtlsHttpTransportFactory(MtlsProvider mtlsProvider)constructor to accept a dynamic certificate provider (such asX509Provider).public synchronized void rebuildContext()to reloadclient certificates and private keys from disk on demand.
DelegatingSSLSocketFactoryso existingNetHttpTransportinstances automatically delegate socket creation (createSocket(...)) to the latest reloaded SSL socket factory without requiring transport reconstruction.Credential Initialization in
IdentityPoolCredentials:new MtlsHttpTransportFactory(x509Provider)directly so credentials benefit from dynamic certificate reloading.STS
401 UnauthorizedRetry Handler inExternalAccountCredentials&StsRequestHandler:.setUnsuccessfulResponseHandler(...)support toStsRequestHandler.Builder.HttpUnsuccessfulResponseHandlerinExternalAccountCredentials.exchangeExternalCredentialForAccessToken(). When an STS exchange over an mTLS transport returns401 Unauthorized, the interceptor invokes((MtlsHttpTransportFactory) transportFactory). rebuildContext()and retries the exchange once per token refresh cycle.Testing & Verification
MtlsHttpTransportFactoryTestverifying constructor null checks,KeyStoreinitialization,MtlsProviderinitialization, and dynamicrebuildContext()delegate reloading.ExternalAccountCredentialsTest#exchangeExternalCredentialForAccessToken_withMtls401_retriesAndRebuildsContextverifying that an initial401 Unauthorizedresponse from STS over an mTLS transport triggersrebuildContext()and succeeds on retry.google-auth-library-java/oauth2_httppass (BUILD SUCCESS).IdentityPoolCredentialsTestpasses cleanly.git diff --checkwith 0 whitespace warnings.