Skip to content

test(dgw): cover credential injection reconnect hops - #1938

Open
irvingouj@Devolutions (irvingoujAtDevolution) wants to merge 9 commits into
refactor/rdp-proxy-credssp-extractfrom
test/cred-injection-reconnect-e2e
Open

test(dgw): cover credential injection reconnect hops#1938
irvingouj@Devolutions (irvingoujAtDevolution) wants to merge 9 commits into
refactor/rdp-proxy-credssp-extractfrom
test/cred-injection-reconnect-e2e

Conversation

@irvingoujAtDevolution

@irvingoujAtDevolution irvingouj@Devolutions (irvingoujAtDevolution) commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Add process-level Gateway tests for DVLS-like preflight, TCP and RDCleanPath injection, NTLM and Kerberos CredSSP, fail-closed missing mappings, and missing krb_kdc without dialing the target.

RDCleanPath cases drive the public ironrdp-agent 0.1.0 CLI over ws://127.0.0.1/jet/rdp.

Issue: DVLS-14697

@irvingoujAtDevolution

Copy link
Copy Markdown
Contributor Author

Implementation notes:

  • Tests live in testsuite/tests/cli/dgw/cred_injection.rs and start a real Gateway with disable_token_validation.
  • DVLS-like /jet/preflight posts provision-credentials and, for Kerberos, provision-connection-options.krb_kdc.
  • The client sends a PCB v2 blob (JWT in v2_payload) plus an X.224 Connection Request with Cookie: mstshash=client-cookie-user.
  • The destination is a loopback TCP peer that records the rewritten mstshash cookie. CredSSP is not completed; sspi-rs / IronRDP are not run as a fake KDC or RDP server.
  • First inject, jet_reuse reconnect (get not take), required-but-expired fail-closed, and unprovisioned ordinary forward are asserted from Gateway logs and the cookie.
  • Kerberos overlapping reconnects must publish the synthetic KDC once for the same provisioning generation; a later provision publishes again.

Note

LLM-assisted content (no human feedback).

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

Adds process-level coverage for Gateway RDP credential injection.

Changes:

  • Tests NTLM injection, reconnect attempts, expiration, and fail-closed routing.
  • Adds mock KDC and CredSSP integration coverage.
  • Extends test configuration and dependencies.

Reviewed changes

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

Show a summary per file
File Description
Cargo.lock Locks new test dependencies.
testsuite/Cargo.toml Adds Kerberos and IronRDP test dependencies.
testsuite/src/dgw_config.rs Exposes Kerberos injection test configuration.
testsuite/tests/cli/dgw/mod.rs Registers new test modules.
testsuite/tests/cli/dgw/cred_injection.rs Adds credential injection lifecycle tests.
testsuite/tests/cli/dgw/cred_injection_kdc.rs Adds mock KDC/CredSSP integration testing.

💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

target.wait_payloads(1).await?;
drop(first);

let _second = connect_rdp_client(gateway.config.tcp_port(), &token).await?;
Comment on lines +160 to +175
let Ok((mut stream, _)) = listener.accept().await else {
break;
};
accepted_task.fetch_add(1, Ordering::SeqCst);
let payloads = Arc::clone(&payloads_task);
tokio::spawn(async move {
let mut buf = vec![0u8; 4096];
// CredSSP cert generation can delay the rewritten X.224 CR.
if let Ok(Ok(n)) = tokio::time::timeout(Duration::from_secs(30), stream.read(&mut buf)).await
&& n > 0
{
payloads.lock().expect("payload mutex").push(buf[..n].to_vec());
}
// Keep the accepted socket open so the proxy can finish writing the CR.
tokio::time::sleep(Duration::from_secs(30)).await;
});
Comment on lines +569 to +572
let tls = connect_ntlm_client(gateway.config.tcp_port(), &token).await?;
complete_ntlm_credssp(tls)
.await
.context("Gateway-facing NTLM CredSSP")?;
Ok(())
}

const CERT_PEM: &str = r#"-----BEGIN CERTIFICATE-----
Comment thread testsuite/Cargo.toml

[dev-dependencies]
base64 = "0.23"
ironrdp-acceptor = "0.10"
Add process-level tests for DVLS-like preflight, first inject,
jet_reuse reconnect, fail-closed missing mappings, and synthetic
KDC generation reuse.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Clippy separated_literal_suffix failed CI lints on the stacked
reconnect tests.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Drive CredSSP through a TCP kdc crate and IronRDP acceptor so
target-leg Kerberos injection is proven, not just log-matched.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Prove both CredSSP hops against mock KDC/RDP, NTLM CredSSP both
legs, and Kerberos fail-closed when the password, KDC, or krb_kdc
is wrong. Token-cache jet_reuse still needs signed JWTs.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Decode AS-REQ/TGS-REQ on the mock KDC (cname, realm, TERMSRV/localhost),
record CredSSP Finished account names and X.224 cookies, and require
/jet/KdcProxy AS-REP plus TGS-REP.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Routing tests now decode X.224 Cookie instead of raw-byte search.
Client-leg Kerberos asserts synthetic-KDC AS-REQ cname. Fail-closed
Kerberos paths require inject-started then no Finished identity.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Decode X.224 cookies, KdcProxy AS/TGS principals, and attribute
KDC-down TCP to Gateway via a separate refusing listener.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Checkout-before-connect on the stack below lets the fail-closed path
prove accepted==0.

Issue: DGW-1900

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Pin the public CLI release and complete NTLM and Kerberos target
CredSSP over ws://127.0.0.1/jet/rdp.

Issue: DGW-1900

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@irvingoujAtDevolution irvingouj@Devolutions (irvingoujAtDevolution) changed the title test(dgw): cover credential injection reconnect test(dgw): cover credential injection reconnect hops Aug 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants