Repository navigation
feat(server): let the embedder decide when a connection gets an auto-reconnect cookie - #2046
Conversation
There was a problem hiding this comment.
Opt-in 'cookie on request' mode is sound: default behavior is unchanged (both predicates are always-true when off), ConnectionInfo is #[non_exhaustive] so the new field is non-breaking, and the issued-cookie tracking is reset per connection before the embedder's events drain. One real conformance/security consequence is published: in on-request mode a connection the embedder never vouches for triggers neither the activation-time send nor the hourly rotation, so commit_auto_reconnect_rotation never regenerates the stored cookie on connect; since verify_auto_reconnect_cookie accepts the current and previous cookies and a verified cookie bypasses credential validation, a prior client's cookie stays valid indefinitely, contrary to MS-RDPBCGR 5.5. Lower-severity items: the new e2e helper duplicates the existing handshake harness (two specialists, merged), the load-bearing reactivation branch is untested, and the unchanged with_auto_reconnect_cookie doc now overstates when the cookie is sen…
- [skeptical] with_auto_reconnect_cookie doc still claims unconditional send at activation — low 🟡 — crates/ironrdp-server/src/builder.rs
The unchanged doc (lines ~439-447) states the server sends the cookie 'right after activation' and generates a fresh random 'whenever a client connects'. With with_auto_reconnect_on_request(true), a builder-provisioned cookie is not sent at activation for a fresh connection (issues_auto_reconnect_at_activation returns false) and no rotation occurs on connect. The new with_auto_reconnect_on_request doc is a bare cross-reference to the setter, so the interaction is not surfaced where an embedder combining both methods would look. Claim-accuracy gap introduced by the behavior change; the doc was not modified by this PR, so line fields are null.
adb4a9c to
5fe1bcb
Compare
There was a problem hiding this comment.
Opt-in, off-by-default mode that defers auto-reconnect cookie issuance to embedder vouching and gates the hourly rotation to vouched connections. Core server state machine is correct: default mode is provably unchanged (both new gates short-circuit true), the per-connection issued flag is not derivable from auto_reconnect_sent, and reactivation preserves eligibility as documented, with e2e coverage in both directions. Three findings survive review: (1) a queued vouch is an unaddressed process-wide event that survives takeover cleanup and is delivered to the replacement connection, handing a usable cookie to a connection that proved nothing; (2) on-request mode deliberately departs from the MS-RDPBCGR 5.5 flush-and-regenerate guarantee for unvouched connections, which is documented but keeps a prior user's cookie usable if an embedder does not vouch for a different user's connection; (3) duplicated cookie watch loops in the new test helper. One optional inlining suggestion was rejected…
|
Update: no rebase needed anymore. picky-krb 0.12.5 was yanked from crates.io (re-released as 0.13.0), so the API check builds again without changes to this branch. PR automation has been re-run here and passes. |
f8443c7 to
eea6a19
Compare
There was a problem hiding this comment.
PR #2046 adds an opt-in auto-reconnect cookie mode to IronRDP's server: `with_auto_reconnect_on_request` / `set_auto_reconnect_on_request` defer cookie issuance until the embedder vouches via `AutoReconnectCookieHandle` or a client returns with a verified cookie; hourly rotation is gated on a new per-connection `auto_reconnect_issued` bit; queued `SetAutoReconnectCookie(Some)` vouches are dropped in `discard_stale_session_events` when on-request mode is active; and `ConnectionInfo::auto_reconnect` exposes verified reconnects. Default behavior is preserved because every new gate short-circuits when the flag is off, and the discard-loop rewrite is behaviorally equivalent for existing events. Tests cover issuance timing, vouch invalidation, stale-vouch dropping, and hourly rotation across reactivation. I independently verified the single code-compressor candidate in pr-head: `connect_active_client` in e2e.rs (lines 1586-1597) is generic over a `FnOnce` connector factory but has exactly o…
…reconnect cookie The server sends an auto-reconnect cookie (MS-RDPBCGR 2.2.4.2) to every connection at activation and reissues it hourly (3.3.6.2). MS-RDPBCGR 5.5 has the cookie sent as soon as the user has been authenticated, but an embedder that accepts a connection before the user has proved anything, for instance to draw its own logon screen after a credential validator hands off, gives that connection a cookie it can later present in place of credentials and skip the screen. RdpServerBuilder::with_auto_reconnect_on_request and RdpServer::set_auto_reconnect_on_request switch to issuing cookies only on request: through AutoReconnectCookieHandle::set once the embedder has authenticated the user, or to a client that came back with a cookie the server verified. The hourly reissue then goes only to a connection that holds a cookie. Off by default, so nothing changes unless an embedder opts in.
connect_active_client took a connector factory, and its only caller used it to apply an optional cookie. It takes the Option of the cookie itself now, which drops the generic parameter, the where clause and the closure at the call site.
d10ff36 to
94ca777
Compare
The auto-reconnect end-to-end test added by Devolutions#2046 builds a TestDisplay literal that predates the new field, so the extra suite stopped compiling once this branch met master.
Summary
RdpServerBuilder::with_auto_reconnect_on_requestandRdpServer::set_auto_reconnect_on_requestswitch to issuing cookies only on request: ThroughAutoReconnectCookieHandle::setonce the embedder has authenticated the user, or to a client that came back with a cookie the server verified. The hourly reissue then goes only to a connection that holds a cookie. Off by default, so nothing changes unless an embedder opts in.ConnectionInfo::auto_reconnecttells the embedder that a connection came back with a verified cookie, so it can admit it without asking again.RdpServer::set_auto_reconnect_on_requestdocuments this contract.Validation
cargo xtask check fmt/lints/tests/typos/locksall pass. New end-to-end tests inironrdp-testsuite-extracover the following. By default the client receives a cookie at activation. On request it receives none until the embedder issues one, and then it does. A cookie the embedder issues invalidates the previous one, so a client presenting the earlier cookie is rejected while the newest is accepted. A vouch the server hasn't read when its connection is replaced doesn't reach the replacement, while a vouch for the live connection still does. The hourly reissue, driven by paused time, still reaches a connection that holds a cookie after a Deactivation-Reactivation pass, and never reaches a connection the embedder did not vouch for. Each test fails if the behaviour it covers is changed. Whether a connection holds a cookie is kept in the connection's own state, so it starts clear for each connection and a Deactivation-Reactivation pass keeps it eligible for the hourly reissue. The client side of the Deactivation-Reactivation sequence intest_deactivation_reactivationis now a sharedrun_reactivationhelper that the new tests reuse, and they connect through the existingconnect_client.ironrdp-testsuite-extraenables tokio'stest-utilfeature for the paused clock.