feat(webauthn): related-origins validation (WebAuthn L3 §5.11)#219
Open
AlfioEmanueleFresta wants to merge 21 commits into
Open
feat(webauthn): related-origins validation (WebAuthn L3 §5.11)#219AlfioEmanueleFresta wants to merge 21 commits into
AlfioEmanueleFresta wants to merge 21 commits into
Conversation
00b7b74 to
b98aa45
Compare
…nt arg Adds the http parameter to FromIdlModel::from_idl_model and the default WebAuthnIDL::from_json; updates the make_credential and get_assertion impls to take it (currently unused, wired in next commit). Updates ceremony examples and existing from_json tests to pass &NoRelatedOriginsClient and .await the calls.
…d get_assertion When the rp.id is not a registrable suffix of the caller's effective domain, call validate_related_origins() per WebAuthn L3 §5.11.1. On success, accept the request; on failure, surface the existing MismatchingRelyingPartyId variant unchanged so callers' pattern matches keep working.
…l and get_assertion
reqwest's referer() defaults to true, so on any redirect chain it would
auto-populate Referer with the previous URL, leaking the RP's well-known
URL to the redirect target. The previous empty-valued Referer default
header did not disable this. Drop the header insertion and call
.referer(false) so no Referer is sent on the initial request or any
redirect, matching WebAuthn L3 \xc2\xa75.11.1 step 2 ("without a referrer").
Extend the trait doc to bind impls to status-200-only and unmodified Content-Type reporting, so a third-party client cannot accidentally feed a 404 body or a synthesised application/json type to the validator.
The cap is hard-coded inside the validator loop, so external callers cannot override it. Reduce to a private const and drop the re-export to avoid committing to the value across breaking changes.
The previous warn!(error = ?err, ...) debug-printed RelatedOriginsError, which can carry reqwest error text (IP/port) and serde_json text (body snippets). Add RelatedOriginsError::kind() that returns a static discriminant and log only that. Downgrade to debug! since most RPs do not host /.well-known/webauthn and the failure is expected noise.
The previous impl re-parsed the listed URL through Origin::parse, which rejects userinfo, non-/ paths, queries and fragments. WebAuthn L3 \xc2\xa75.11.1 step 4.f defers to HTML \xc2\xa77.5 same-origin, which compares only scheme, host and port. Compare those three directly so a listed entry like "https://example.com/foo" can match the caller. Add a test.
Symmetric to label_cap_blocks_sixth_distinct_label_match. Asserts that the 5th distinct label still satisfies step 4.e's size < max check, so an off-by-one regression on the cap is caught by tests.
The body asserts that an IPv6 listed entry is silently skipped at step 4.c/4.d (no registrable label), not that same-origin matches. Rename to match and rephrase the comment.
…d_origins Mirror NoRelatedOriginsClient's placement: under the same feature gate, expose ReqwestRelatedOriginsClient (and HttpPolicy) at the related_origins module root so consumers do not need the http:: submodule path.
…iginsClient Using NoRelatedOriginsClient in the bundled examples taught readers the wrong default. Wire up the reqwest-backed convenience client instead, gate the three webauthn ceremony examples on the related-origins-client feature, and update the README run commands. Also re-exports HttpPolicy and ReqwestRelatedOriginsClient at ops::webauthn so examples import from a single path.
…egration test Swap brand.com/app.brand.org for example.org/app.example.com. RFC 2606 reserves example.* for documentation, so it cannot accidentally collide with a real party. The two-eTLD shape that exercises the related-origins fetch path is preserved.
…nFetchError The trait's old return type was the full RelatedOriginsError, but four of its five variants (UnexpectedContentType, MalformedJson, MalformedDocument, NoMatchingOrigin) are produced inside validate_related_origins after the fetch returns. Implementers had no reason to ever emit them. Introduce WellKnownFetchError with the variants a fetcher can actually emit (Transport, Status, BodyTooLarge, NotSupported) and let RelatedOriginsError wrap it via a Fetch variant with #[from]. The reqwest client now distinguishes non-200 status from transport faults and from body-cap hits without stringifying everything. Also drops RelatedOriginsError::kind(); the two debug! call sites switch to logging the Display form of the error directly.
05f055e to
2a4d4e5
Compare
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.
Implements WebAuthn L3 §5.11 "Related Origins": when a request's rp.id is not a registrable suffix of the caller's effective domain, libwebauthn now fetches the RP's
.well-known/webauthndocument and accepts the request if a listed origin matches the caller.Closes #160. Stacked on #215; depends on its public-suffix-list trait. Based on #173 by @HarveyOrourke15.
The HTTP fetcher is pluggable via a trait. A reqwest-backed default ships behind the optional
related-origins-clientcargo feature so the core crate stays HTTP-client-free.Note: the JSON-request parsing trait becomes async and gains an HTTP client parameter; downstream consumers will need a one-line update at call sites.