pub struct ValidatedClientIdDocument { /* private fields */ }cimd only.Expand description
A document that passed every check in this module. It cannot be constructed any other way.
That is section 4.4’s caching rule made structural rather than remembered: the only value a host can hold is one that validated, so “MUST NOT cache an invalid or malformed document” is something the type system says rather than something a comment asks for.
Implementations§
Source§impl ValidatedClientIdDocument
impl ValidatedClientIdDocument
Sourcepub fn validate(
fetched_from: &ClientIdUrl,
body: &[u8],
policy: &CimdPolicy,
) -> Result<Self, CimdError>
pub fn validate( fetched_from: &ClientIdUrl, body: &[u8], policy: &CimdPolicy, ) -> Result<Self, CimdError>
Validate body as the client identifier metadata document fetched from fetched_from.
§fetched_from is where the bytes CAME FROM, not what was requested
This is the one signature decision in the module worth defending. Section 4.1 compares the
document’s client_id to the URL the document was retrieved from, and a host that followed
a redirect — which section 4 forbids — retrieved it from somewhere else. Passing the URL
the host actually GOT the bytes from therefore turns the most common redirect violation
into a CimdError::ClientIdMismatch instead of a silent acceptance.
It does NOT enforce the no-redirects rule. A redirect chain that ends at the same URL still passes, and a host that passes the requested URL after following a redirect elsewhere defeats the check entirely. Not following redirects remains the host’s duty; this only means that getting it wrong is usually caught.
§The comparison is byte equality
RFC 3986 section 6.2.1 SIMPLE STRING COMPARISON, and nothing else. A client_id that
differs from the fetch URL by a trailing slash, by the case of the host, or by
percent-encoding is REFUSED, not normalised. Normalising any of them would mean two
distinct strings name one client, which is the property an attacker needs: it is what lets
a document published at one URL answer for another.
§Every other check, and where it comes from
- Section 6.6:
bodyis at mostCimdPolicy::max_document_bytes. - Section 4.1: the body is a JSON object, and
client_idis present. - Section 4.1:
client_secretandclient_secret_expires_atare absent. - Section 4.1:
jwksandjwks_uriare absent, which is this BUILD’s limit rather than the draft’s rule; seeCimdError::KeyMaterialPresent. - Section 4.1:
token_endpoint_auth_methodis not a shared-symmetric method. - Section 4.1: everything else is the RFC 7591 section 2 registry, so it goes through
crate::registration’s validator — the SAME one, not a copy: redirect URIs must be absolute with no fragment and at mostcrate::MAX_REGISTERED_REDIRECT_URISof them,grant_typesandresponse_typesmust correspond, the scope must be within the policy’s ceiling, and asoftware_statementis refused. - Section 6.1:
redirect_urisare same-origin withfetched_from, unless the policy says otherwise.
§The RFC 7591 default this deliberately does not take
RFC 7591 section 2 says an ABSENT token_endpoint_auth_method means client_secret_basic.
Applied literally here that would refuse every document that omits the member, because
section 4.1 forbids exactly that value. So an absent member is read as none: a document
anyone can GET establishes no shared secret, so none is the only method it could ever
have meant, and the resulting client is public. Nothing is accepted-and-ignored by this —
an EXPLICIT shared-secret method is still a refusal.
Sourcepub fn client_id_url(&self) -> &ClientIdUrl
pub fn client_id_url(&self) -> &ClientIdUrl
The client identifier this document belongs to, which is the URL it was fetched from.
Sourcepub fn to_client(&self) -> Client
pub fn to_client(&self) -> Client
The Client a host installs in its own crate::store::Storage for this authorization
request.
Always ClientAuth::Public, and no document that reached here could have been anything
else. Section 4.1 forbids the shared-secret methods outright; the one credential the draft
DOES permit — a public key in jwks/jwks_uri — is refused by
ValidatedClientIdDocument::validate rather than dropped, precisely so that this line
stays true by construction instead of by silently discarding a member. So a CIMD client
proves possession of nothing and the flow compensates with PKCE exactly as it does for a
native app. See CimdError::KeyMaterialPresent.
registration is None. That field means “created by RFC 7591 dynamic registration”, and
this client was not: there is no registration access token, and RFC 7592 read, update and
delete have no meaning for a client that edits its own document. Setting it would advertise
a management surface that does not exist.
default_scopes is EMPTY rather than the document’s scope. RFC 6749 section 3.3’s server
default is a deployment’s decision about what a request that names no scope receives, and a
document the client wrote is not a deployment decision; allowed_scopes is the ceiling and
is where the document’s scope lands.
Trait Implementations§
Source§impl Clone for ValidatedClientIdDocument
impl Clone for ValidatedClientIdDocument
Source§fn clone(&self) -> ValidatedClientIdDocument
fn clone(&self) -> ValidatedClientIdDocument
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read more