Skip to content

fix(xtest): detect java dpop support via supports subcommand - #558

Merged
dmihalcik-virtru merged 1 commit into
mainfrom
java-dpop-supports-detection
Jul 14, 2026
Merged

fix(xtest): detect java dpop support via supports subcommand#558
dmihalcik-virtru merged 1 commit into
mainfrom
java-dpop-supports-detection

Conversation

@dmihalcik-virtru

@dmihalcik-virtru dmihalcik-virtru commented Jul 14, 2026

Copy link
Copy Markdown
Member

Problem

The java-sdk removed the user-facing --dpop / --dpop-key CLI flags in opentdf/java-sdk#374. DPoP is now always-on by default, and capability is exposed through the supports subcommand instead.

The Java wrapper's supports dpop case still detects DPoP by grepping help encrypt for the --dpop flag:

dpop)
  set -o pipefail
  java -jar "$SCRIPT_DIR"/cmdline.jar help encrypt | grep -iE -- '--dpop'
  exit $?
  ;;

With the flags gone this grep finds nothing, exits 1, and xtest skips java DPoP tests:

SKIPPED [2] tdfs.py:619: java@... sdk doesn't yet support [dpop]

The sibling dpop_nonce_challenge case already delegates to the supports subcommand and is unaffected.

Fix

Detect dpop the same way dpop_nonce_challenge already does — via the supports subcommand, whose exit code is the capability contract (0 = supported, 1 = not):

dpop)
  java -jar "$SCRIPT_DIR"/cmdline.jar supports dpop
  exit $?
  ;;

set -o pipefail is dropped since there's no longer a pipe.

Verification

With a current java cmdline.jar installed: ./cli.sh supports dpop; echo $? prints 0, and dpop_nonce_challenge still returns 0. Only xtest/sdk/java/cli.sh changes; other SDK wrappers are untouched.

Summary by CodeRabbit

  • Bug Fixes
    • Improved detection of DPoP support in the Java CLI feature probe.
    • Prevents incorrect results caused by relying on help output and flag matching.

The java-sdk removed the user-facing --dpop/--dpop-key CLI flags
(opentdf/java-sdk#374); DPoP is now always-on and capability is
exposed through the `supports` subcommand. The old detector grepped
`help encrypt` for --dpop, which now finds nothing and marks java as
not supporting dpop. Delegate to `cmdline.jar supports dpop` to match
the existing dpop_nonce_challenge case.

Signed-off-by: Dave Mihalcik <dmihalcik@virtru.com>
@dmihalcik-virtru
dmihalcik-virtru requested review from a team as code owners July 14, 2026 14:13
@sonarqubecloud

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot 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.

Code Review

This pull request simplifies the 'dpop' support check in the xtest/sdk/java/cli.sh script. It replaces a pipeline that grepped the help output of the encrypt command with a direct call to supports dpop on the Java command-line utility. There are no review comments, and I have no additional feedback to provide.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

@coderabbitai

coderabbitai Bot commented Jul 14, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 41c6e600-0cb2-4dbf-ad95-043b83024161

📥 Commits

Reviewing files that changed from the base of the PR and between 66920c7 and 09e7ac0.

📒 Files selected for processing (1)
  • xtest/sdk/java/cli.sh

📝 Walkthrough

Walkthrough

The Java CLI script’s supports dpop probe now directly invokes the CLI’s DPoP support command instead of searching encryption help output for a flag.

Changes

DPoP feature probing

Layer / File(s) Summary
Direct DPoP support check
xtest/sdk/java/cli.sh
The dpop feature probe now runs java -jar ... supports dpop directly, removing the previous help-output grep and pipefail guard.

Estimated code review effort: 1 (Trivial) | ~3 minutes

Possibly related PRs

Suggested reviewers: sujankota

Poem

I’m a bunny with a probe to run,
DPoP support checked direct in the sun.
No grep through help, no flags to seek,
One simple command makes the check sleek.
Hop, hop—cleaner logic this week!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: switching Java DPoP capability detection to the supports subcommand.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch java-dpop-supports-detection

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@dmihalcik-virtru
dmihalcik-virtru merged commit 9ed7af1 into main Jul 14, 2026
22 checks passed
@dmihalcik-virtru
dmihalcik-virtru deleted the java-dpop-supports-detection branch July 14, 2026 16:43
dmihalcik-virtru added a commit to opentdf/java-sdk that referenced this pull request Jul 27, 2026
## Summary

Adds comprehensive DPoP (RFC 9449) support to the Java SDK as part of
the Keycloak v26 upgrade and DPoP implementation effort.

**Related Jira:** https://virtru.atlassian.net/browse/DSPX-3397
**Test Scenario:** xtest/scenarios/DSPX-3397.yaml (in tests repo)
**Green e2e Test Run:**
https://github.com/opentdf/tests/actions/runs/29624686479

## Changes

### Core DPoP proof generation
- **TokenSource**: Generates RFC 9449-compliant DPoP proofs via Nimbus
`DefaultDPoPProofFactory`, with claims `jti`, `htm`, `htu`, `iat` (plus
`ath` for resource endpoints).
- `htu` claim strips query and fragment per RFC 9449 §4.2.
- Token scheme (`DPoP` vs `Bearer`) modeled as an enum; token + scheme
read atomically to avoid a refresh-time data race.

### Server-issued nonce handling (full retry — implemented)
- **Token endpoint (§8.2)**: On `use_dpop_nonce`, retries the token
request once with the AS-provided nonce.
- **Resource server (§9)**: okhttp-level interceptor retries once with
the `DPoP-Nonce` from a `WWW-Authenticate` challenge; drops the stale
proof header on the retry.
- Per-origin nonce cache (keyed by scheme/host/port, with default-port
normalization); nonces cached from responses regardless of status.

### Key configuration & validation
- **SDKBuilder**: `dpopKey(...)` accepts a caller-supplied RSA **or EC**
key; auto-generates an ephemeral key if none provided. An EC DPoP key
triggers a separate RSA-2048 SRT key.
- **DpopKeyValidation** (new): central validation — rejects public-only
JWKs, enforces key-type/algorithm compatibility, infers the EC algorithm
from the curve.
- Connect-GET disabled on the authenticated client to protect the `htm`
claim.

### Bearer fallback
- Falls back to `Bearer` scheme when the AS returns a non-DPoP-bound
token, with a warning; stale DPoP proof is stripped so a Bearer request
never carries a DPoP header.
- Fails loudly when DPoP is requested but the well-known omits
`platform_issuer`.

### CLI (cmdline)
DPoP is **always-on** for any authenticated client, so the CLI needs no
DPoP flags:
- The SDK auto-generates a DPoP key when none is configured, so
`encrypt`, `decrypt`, and metadata commands are sender-constrained
without any opt-in.
- No `--dpop` / `--dpop-key` flags are exposed (an earlier revision
added them; they were removed together with `CliDpopOptions` since they
served no purpose once DPoP is unconditional). This mirrors the go-sdk
direction in opentdf/platform#3581, which likewise dropped otdfctl's
`--dpop` parameters.
- **Feature detection via the `supports` subcommand** (no help-text
scraping required):
  - `tdf supports <feature>` exits `0` if supported, `1` otherwise.
- `tdf supports` with no argument lists all supported feature names, one
per line.
- `--json` emits a JSON object mapping feature name → boolean, e.g.
`{"dpop":true}` or, with no argument,
`{"dpop":true,"dpop_nonce_challenge":true}`.

## Feature Detection

```bash
tdf supports dpop                   # exits 0 if supported
tdf supports dpop_nonce_challenge   # exits 0 if supported
tdf supports                        # lists supported features, one per line
tdf supports --json                 # {"dpop":true,"dpop_nonce_challenge":true}
tdf supports dpop --json            # {"dpop":true}
```

## Testing

New coverage: `TokenSourceTest`, `DPoPRetryInterceptorTest`,
`AuthInterceptorConnectPathTest` (Kotlin), and `CommandTest` — covering
nonce caching/origin isolation, both retry paths, EC/RSA key handling,
and the `supports` subcommand (bare exit codes, no-arg listing, and
`--json` output).

## Related PRs
- **tests repo**: opentdf/tests#558 — updates the xtest Java `cli.sh` to
detect `dpop` via `supports dpop` instead of grepping the removed
`--dpop` flag.
- **platform repo**: DSPX-3397-platform-service,
DSPX-3397-platform-go-sdk (opentdf/platform#3581)
- **web-sdk repo**: DSPX-3397-web-sdk

## Checklist
- [x] DPoP proof generation (htm/htu/iat/jti/ath)
- [x] Per-origin nonce caching
- [x] Full 401/nonce retry — token endpoint (§8.2) and resource server
(§9)
- [x] RSA and EC DPoP keys; caller-supplied or ephemeral
- [x] Central DPoP key validation
- [x] Bearer fallback for non-DPoP-bound tokens
- [x] Always-on DPoP; no CLI flags needed (removed `--dpop`/`--dpop-key`
+ `CliDpopOptions`)
- [x] `supports` feature detection: bare exit code, no-arg listing,
`--json`
- [ ] xtest integration tests (pending tests repo coordination —
opentdf/tests#558)


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Added a `supports` CLI subcommand (plain list or `--json` feature
support results with canonical casing).
  * Added `-v/--verbose` for more detailed error output.
* Improved DPoP handling: configurable DPoP keys/algorithms, conditional
DPoP headers, nonce caching, and single-retry behavior for
`use_dpop_nonce` (with correct Bearer downgrade).
* Added stricter validation and clearer errors for missing CLI
credentials and incompatible DPoP configuration.
* **Documentation**
  * Updated build instructions for setting `JAVA_HOME` via Homebrew.
* **Testing / Build**
* Added/expanded CLI and SDK test coverage and explicit test
dependencies for Java/Kotlin.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Signed-off-by: Dave Mihalcik <dmihalcik@virtru.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants