Skip to main content

ValidatedClientIdDocument

Struct ValidatedClientIdDocument 

Source
pub struct ValidatedClientIdDocument { /* private fields */ }
Available on crate feature 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

Source

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: body is at most CimdPolicy::max_document_bytes.
  • Section 4.1: the body is a JSON object, and client_id is present.
  • Section 4.1: client_secret and client_secret_expires_at are absent.
  • Section 4.1: jwks and jwks_uri are absent, which is this BUILD’s limit rather than the draft’s rule; see CimdError::KeyMaterialPresent.
  • Section 4.1: token_endpoint_auth_method is 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 most crate::MAX_REGISTERED_REDIRECT_URIS of them, grant_types and response_types must correspond, the scope must be within the policy’s ceiling, and a software_statement is refused.
  • Section 6.1: redirect_uris are same-origin with fetched_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.

Source

pub fn client_id_url(&self) -> &ClientIdUrl

The client identifier this document belongs to, which is the URL it was fetched from.

Source

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

Source§

fn clone(&self) -> ValidatedClientIdDocument

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for ValidatedClientIdDocument

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Eq for ValidatedClientIdDocument

Source§

impl PartialEq for ValidatedClientIdDocument

Source§

fn eq(&self, other: &ValidatedClientIdDocument) -> bool

Equality operator ==. Read more
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Inequality operator !=. Read more
Source§

impl StructuralPartialEq for ValidatedClientIdDocument

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> FromRef<T> for T
where T: Clone,

Source§

fn from_ref(input: &T) -> T

Converts to this type from a reference to the input type.
Source§

impl<A, B, T> HttpServerConnExec<A, B> for T
where B: Body,

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.