feat(qwp): refreshing token providers for Entra ID authentication - #102
Draft
bluestreak01 wants to merge 3 commits into
Draft
bluestreak01 wants to merge 3 commits into
bluestreak01 wants to merge 3 commits into
Conversation
Add a cross-language specification for QWP clients that authenticate with rotating bearer tokens (Microsoft Entra ID managed identities and service principals), plus the Java findings and implementation plan. - design/qwp-token-provider-spec.md (v0.3, decisions resolved): the token-source contract, a proactively refreshing shared token cache, when clients fetch tokens, failure policy by phase (one retry after 401), connect-string keys (token_provider, azure_resource, azure_client_id), connection health, an optional authentication- outage deadline, redaction rules and conformance tests C1-C23. - design/entra-id-qwp-auth.md: findings for the Java client with code references, the design rationale, and the four-step Java plan (§10). Security-relevant server findings are reported privately and are not part of this change.
| AzureTokenProviderFactory factory = new AzureTokenProviderFactory(); | ||
| Map<String, String> params = new HashMap<>(); | ||
| params.put(TokenProviderSpec.KEY_AZURE_RESOURCE, "api://qdb"); | ||
| params.put(TokenProviderSpec.KEY_AZURE_CLIENT_ID, "0a1b2c3d-4e5f-6a7b-8c9d-0e1f2a3b4c5d"); |
Contributor
There was a problem hiding this comment.
🛑 Gitleaks has detected a secret with rule-id generic-api-key in commit 576383b.
If this secret is a true positive, please rotate the secret ASAP.
If this secret is a false positive, you can add the fingerprint below to your .gitleaksignore file and commit the change to this branch.
echo 576383b498f6ab57f6d34fae2e696f2f8210ae08:azure/src/test/java/io/questdb/client/azure/test/AzureTokenSourceTest.java:generic-api-key:137 >> .gitleaksignore
Implement the dynamic-credential specification (design/qwp-token-provider-spec.md, v0.3) and the four-step Java plan in design/entra-id-qwp-auth.md, section 10. - Token cache: RefreshingTokenProvider, ExpiringToken, TokenSource and TokenUnavailableException. Proactive jittered refresh at about half the token lifetime, a 60 s hand-out floor, single-flight cold waits bounded by cold_wait, jittered backoff honouring Retry-After, rate-limited forced refresh, and token redaction everywhere. - Client integration: one immediate same-endpoint retry after a refreshable 401 (WWW-Authenticate aware; never for a 403 or a static credential) on every ingest connect path, orphan drains included, and on egress connect and failover. SYNC startup retries a retryable provider failure within its budget (D6); any other provider exception still fails fast (D8). Egress errors name the failure class, and a query client whose failover reconnect failed reconnects on its next execute() instead of staying unusable (the suspected dead pooled worker, reproduced by a test before the fix). - Connect string: token_provider, azure_resource and azure_client_id on both clients (wss:: only; exclusive with static credentials and application-supplied providers), resolved through a ServiceLoader SPI and a process-wide ref-counted registry with a 60 s linger. Validation never fetches a token. - New optional module azure/ (org.questdb:questdb-client-azure): token_provider=azure on DefaultAzureCredential with the spec's error classification. Java 8 floor, released together with the client. - Connection health: Sender.health(), QwpQueryClient.health() and an aggregate QuestDB.health(); an optional auth_failure_max_duration_millis deadline for authentication outages. - Tests for conformance scenarios C1-C23, plus a TLS mode for the test WebSocket server (its key is generated at test time). README and design docs updated; the spec's Appendix B now names the published artifact org.questdb:questdb-client-azure.
bluestreak01
force-pushed
the
feat/qwp-entra-token-provider
branch
from
October 2, 2026 10:15
576383b to
c9f2b96
Compare
The spec classified Azure Identity's "no credential available in the chain" as permanent (section 7.5), while section 4 calls network failures and IMDS 404/410 retryable. Inside DefaultAzureCredential an unreachable IMDS produces exactly that message: the chain probes IMDS once, with a short timeout and no retries, so a transient IMDS outage failed a SYNC startup fast. Spec v0.4 follows Azure Identity's own split between fail-fast discovery and a resilient single credential: - 7.1, 7.2: a new key, azure_credential (default, managed_identity, workload_identity, environment), with its validation rules. - 7.5: library errors are classified by how the credential was selected. With one credential, configuration errors are permanent and endpoint or network failures retryable. In the discovery chain, "no credential available" is retryable and the client warns once. Errors should carry the library's innermost reason. - 4: a source that discovers its credential by probing must not treat "nothing found" as permanent on that evidence alone. - 10: conformance test C24. 12: decision D10, which records why an SMBIOS host check was rejected. Appendix B: the Java binding. Appendix D: precedents from Azure Identity, MongoDB, Google, AWS and Apache Druid. The Java implementation still follows v0.3.
Contributor
[PR Coverage check]😍 pass : 1210 / 1356 (89.23%) file detail
|
This branch has not been deployed
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.
What this is
Support for QWP clients that authenticate with rotating bearer tokens: Microsoft Entra ID managed identities and service principals, typically obtained through
DefaultAzureCredential. No QuestDB credentials are stored.Today a static
token=is captured once. Once it expires, every reconnect presents the dead token. The existingHttpTokenProviderhook already re-pulls a token on every connect round. What's missing is an expiry-aware shared cache, failure classification, a refresh signal on 401, and a connect-string way to select a provider.Status: draft, spec only
This PR currently contains the design. The Java implementation follows in the steps below.
design/qwp-token-provider-spec.md: the cross-language specification (v0.3, all decisions resolved). Other clients (Rust/Python, Go, .NET, Node) implement this document.design/entra-id-qwp-auth.md: findings for the Java client (with code references), the design rationale, and the Java implementation plan (§10).Plan (design doc §10; test IDs refer to spec §10)
ExpiringToken,TokenSource,RefreshingTokenProvider,TokenUnavailableException. Tests C1–C8, C20.onTokenRejected. Tests C9–C16, C23.token_provider,azure_resource,azure_client_id), the shared registry, and thequestdb-client-azuremodule. Tests C17–C19.Separate tickets, not in this PR:
Security-relevant server findings were reported privately (see
SECURITY.md) and are not part of this PR.