Skip to main content

Module document

Module document 

Source
Expand description

Fetch, validate, and cache OAuth Client ID Metadata Documents (CIMD).

Split into independently testable layers:

  1. ssrf::validate_url_shape — static URL checks, no network (tested in isolation in cimd::ssrf).
  2. resolve_and_validate_address — real DNS resolution, bounded by a timeout, rejecting the whole resolved-address set if any address is private. Tested with literal loopback/private hostnames — no real network access needed to prove a rejection; a real “successful public resolution” is not unit-tested here (see the plan’s Global Constraints for why: no network access in CI).
  3. fetch_via_pinned_address / fetch_document_at — given an ALREADY resolved+validated address, builds a pinned/no-proxy/ no-redirect client and does the GET + peer-recheck + streaming-cap + parse + validate. Tested against a local wiremock server by pointing the pin directly at its real bound address — this deliberately bypasses DNS resolution (same as production code does once step 2 has already resolved+validated an address), so it needs no network and no HTTPS certificate.

fetch_and_validate_client_metadata composes all three for the real production path, with per-key single-flight coordination and a short negative-result cooldown for cached failures — the mechanism mirrors crate::upstream::cache::OauthClientCache’s build_locks pattern, but unlike that cache’s (upstream_name, subject) key (bounded by operator config and authenticated sessions, not attacker-controlled), client_id here is an anonymous, attacker-controlled URL — see DocumentCache’s own doc for how that difference is handled.

Structs§

ClientMetadataDocument
DocumentCache
Single-flight, TTL-and-negative-cached store for fetched CIMD documents, keyed by the requested URL. Mirrors crate::upstream::cache::OauthClientCache’s build_locks pattern: concurrent callers for the same never-cached (or just-expired) URL serialize on a per-key lock so only one of them actually performs the DNS resolution + fetch; the rest wait for and reuse that result.

Enums§

CimdError

Functions§

fetch_and_validate_client_metadata
Production entry point: single-flight-locked cache lookup (including a short negative-result cooldown for cached failures), else SSRF-validate the URL shape, resolve+validate DNS (for domain hosts) or use the already-validated IP literal directly, fetch via fetch_via_pinned_address, and cache the result either way.
is_cimd_client_id
Cheap detection heuristic: a CIMD client_id is an https:// URL. soma-auth’s own DCR-issued client_ids are opaque base64url tokens (random_token(18) in authorize::register_client) and can never start with https://.
resolve_and_validate_address
Resolve host:port via DNS (bounded by DNS_TIMEOUT) and return the first resolved address, rejecting the entire result set if any resolved address is private/loopback/etc — a hostname resolving to a mix of public and private addresses is treated as untrusted outright rather than cherry-picking a public one, since DNS load-balancing could non-deterministically prefer the private one on a subsequent lookup even though this specific call pins one address.