diff --git a/src/client.rs b/src/client.rs index e93e93f..439de70 100644 --- a/src/client.rs +++ b/src/client.rs @@ -316,7 +316,7 @@ impl Client { } /// Get a userinfo json document for a given token at the provider's - /// userinfo endpoint. Returns [Standard Claims](https://openid.net/specs/openid-connect-basic-1_0.html#StandardClaims) as [Userinfo] struct. + /// userinfo endpoint. Returns [Standard Claims](https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims) as [Userinfo] struct. /// /// # Errors /// @@ -334,7 +334,7 @@ impl Client { } /// Get a userinfo json document for a given token at the provider's - /// userinfo endpoint. Returns [UserInfo Response](https://openid.net/specs/openid-connect-basic-1_0.html#UserInfoResponse) + /// userinfo endpoint. Returns [UserInfo Response](https://openid.net/specs/openid-connect-core-1_0.html#UserInfoResponse) /// including non-standard claims. The sub (subject) Claim MUST always be /// returned in the UserInfo Response. /// diff --git a/src/configurable.rs b/src/configurable.rs index 5a4cbfc..6b6d41f 100644 --- a/src/configurable.rs +++ b/src/configurable.rs @@ -1,5 +1,16 @@ use crate::Config; +/// A trait for types that can be configured. +/// +/// This trait defines a method `config` which returns a reference to a +/// `Config`. pub trait Configurable { + /// Returns a reference to the configuration of this type. + /// + /// # Examples + /// + /// ``` + /// let config = MyType::default().config(); + /// ``` fn config(&self) -> &Config; } diff --git a/src/custom_claims.rs b/src/custom_claims.rs index e1658d7..029df14 100644 --- a/src/custom_claims.rs +++ b/src/custom_claims.rs @@ -37,6 +37,7 @@ use crate::{Claims, StandardClaims}; /// /// See full example: [openid-example:custom_claims](https://github.com/kilork/openid-example/blob/master/examples/custom_claims.rs) pub trait CustomClaims: Serialize + DeserializeOwned { + /// The standard claims. fn standard_claims(&self) -> &StandardClaims; } diff --git a/src/discovered.rs b/src/discovered.rs index 80c7d3b..6df4413 100644 --- a/src/discovered.rs +++ b/src/discovered.rs @@ -4,6 +4,10 @@ use url::Url; use crate::{error::Error, Config, Configurable, Provider}; +/// A discovered provider. +/// +/// This struct is used to store configuration for a provider that was +/// discovered using the discovery protocol. #[derive(Debug, Clone)] pub struct Discovered(Config); diff --git a/src/display.rs b/src/display.rs index b5253c2..7623371 100644 --- a/src/display.rs +++ b/src/display.rs @@ -1,10 +1,23 @@ -/// The four values for the preferred display parameter in the Options. See spec -/// for details. +/// The four values for the preferred `display` parameter in the Options. See +/// spec for details. +/// +/// See: [OpenID Connect Core 1.0: Authentication Request](https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest) #[derive(Debug, Clone, Copy)] pub enum Display { + /// The Authorization Server SHOULD display the authentication and consent + /// UI consistent with a full User Agent page view. If the display parameter + /// is not specified, this is the default display mode. Page, + /// The Authorization Server SHOULD display the authentication and consent + /// UI consistent with a popup User Agent window. The popup User Agent + /// window should be of an appropriate size for a login-focused dialog and + /// should not obscure the entire window that it is popping up over. Popup, + /// The Authorization Server SHOULD display the authentication and consent + /// UI consistent with a device that leverages a touch interface. Touch, + /// The Authorization Server SHOULD display the authentication and consent + /// UI consistent with a "feature phone" type display. Wap, } diff --git a/src/error.rs b/src/error.rs index 1ee62a9..9ba4013 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,5 +1,5 @@ /*! -OAuth 2.0 errors. +Library errors for OAuth 2.0 and OpenID. */ use std::{error, fmt}; @@ -91,6 +91,8 @@ impl From<&str> for OAuth2ErrorCode { } } } + +/// Client side error. #[derive(Debug)] pub enum ClientError { /// IO error. @@ -165,118 +167,213 @@ use thiserror::Error; #[cfg(feature = "uma2")] use crate::uma2::Uma2Error; +/// openid library error. +/// +/// Wraps different sources of errors under one error type for library. #[derive(Debug, Error)] pub enum Error { + /// [biscuit] errors. #[error(transparent)] Jose(#[from] Jose), + /// [reqwest] errors. #[error(transparent)] Http(#[from] Http), + /// [serde_json] errors. #[error(transparent)] Json(#[from] Json), + /// Decode token error. #[error(transparent)] Decode(#[from] Decode), + /// Validation error. #[error(transparent)] Validation(#[from] Validation), + /// Errors related to userinfo endpoint. #[error(transparent)] Userinfo(#[from] Userinfo), + /// Errors related to introspection endpoint. #[error(transparent)] Introspection(#[from] Introspection), + /// Secure connection is required. #[error("Url must use TLS: '{0}'")] Insecure(::reqwest::Url), + /// The scope must contain `openid`. #[error("Scope must contain Openid")] MissingOpenidScope, + /// Path segments in url is cannot-be-a-base. #[error("Url: Path segments is cannot-be-a-base")] CannotBeABase, + /// Client side error. #[error(transparent)] ClientError(#[from] ClientError), } +/// Decode token error. #[derive(Debug, Error)] pub enum Decode { - #[error("Token Missing a Key Id when the key set has multiple keys")] + /// Token missing a key id when the key set has multiple keys. + #[error("Token missing a key id when the key set has multiple keys")] MissingKid, + /// Token wants this key id not in the key set. #[error("Token wants this key id not in the key set: {0}")] MissingKey(String), + /// JWK Set is empty. #[error("JWK Set is empty")] EmptySet, + /// No support for EC keys yet. #[error("No support for EC keys yet")] UnsupportedEllipticCurve, + /// No support for Octet key pair yet. #[error("No support for Octet key pair yet")] UnsupportedOctetKeyPair, } +/// Validation failure related to mismatch of values, missing values or expired +/// values. #[derive(Debug, Error)] pub enum Validation { + /// Mismatch in token attribute. #[error(transparent)] Mismatch(#[from] Mismatch), + /// Missing required token attribute. #[error(transparent)] Missing(#[from] Missing), + /// Token expired. #[error(transparent)] Expired(#[from] Expiry), } +/// Mismatch in token attribute. #[derive(Debug, Error)] pub enum Mismatch { + /// Client ID and Token authorized party mismatch. #[error("Client ID and Token authorized party mismatch: '{expected}', '{actual}'")] - AuthorizedParty { expected: String, actual: String }, + AuthorizedParty { + /// Expected value. + expected: String, + /// Actual value. + actual: String, + }, + /// Configured issuer and token issuer mismatch. #[error("Configured issuer and token issuer mismatch: '{expected}', '{actual}'")] - Issuer { expected: String, actual: String }, + Issuer { + /// Expected value. + expected: String, + /// Actual value. + actual: String, + }, + /// Given nonce does not match token nonce. #[error("Given nonce does not match token nonce: '{expected}', '{actual}'")] - Nonce { expected: String, actual: String }, + Nonce { + /// Expected value. + expected: String, + /// Actual value. + actual: String, + }, } -#[derive(Debug, Error)] +/// Missing required token attribute. +#[derive(Debug, Clone, Copy, Error)] pub enum Missing { + /// Token missing Audience. #[error("Token missing Audience")] Audience, + /// Token missing AZP. #[error("Token missing AZP")] AuthorizedParty, + /// Token missing Auth Time. #[error("Token missing Auth Time")] AuthTime, + /// Token missing Nonce. #[error("Token missing Nonce")] Nonce, } -#[derive(Debug, Error)] +/// Token expiration variants. +#[derive(Debug, Clone, Copy, Error)] pub enum Expiry { + /// Token expired. #[error("Token expired at: {0}")] Expires(::chrono::DateTime<::chrono::Utc>), + /// Token is too old. #[error("Token is too old: {0}")] MaxAge(::chrono::Duration), + /// Token exp is not valid UNIX timestamp. #[error("Token exp is not valid UNIX timestamp: {0}")] NotUnix(i64), } +/// Errors related to userinfo endpoint. #[derive(Debug, Error)] pub enum Userinfo { + /// Config has no userinfo url. #[error("Config has no userinfo url")] NoUrl, + /// The UserInfo Endpoint MUST return a content-type header to indicate + /// which format is being returned. #[error("The UserInfo Endpoint MUST return a content-type header to indicate which format is being returned")] MissingContentType, + /// Not parsable content type header. #[error("Not parsable content type header: {content_type}")] - ParseContentType { content_type: String }, + ParseContentType { + /// Content type header value. + content_type: String, + }, + /// Wrong content type header. + /// + /// The following are accepted content types: `application/json`, + /// `application/jwt`. #[error("Wrong content type header: {content_type}. The following are accepted content types: application/json, application/jwt")] - WrongContentType { content_type: String, body: Vec }, + WrongContentType { + /// Content type header value. + content_type: String, + /// Request body for analyze. + body: Vec, + }, + /// Token and Userinfo Subjects mismatch. #[error("Token and Userinfo Subjects mismatch: '{expected}', '{actual}'")] - MismatchSubject { expected: String, actual: String }, + MismatchSubject { + /// Expected token subject value. + expected: String, + /// Actual token subject value. + actual: String, + }, + /// The sub (subject) Claim MUST always be returned in the UserInfo + /// Response. #[error(transparent)] MissingSubject(#[from] StandardClaimsSubjectMissing), } -#[derive(Debug, Error)] +/// The sub (subject) Claim MUST always be returned in the UserInfo Response. +#[derive(Debug, Copy, Clone, Error)] #[error("The sub (subject) Claim MUST always be returned in the UserInfo Response")] pub struct StandardClaimsSubjectMissing; +/// Introspection error details. #[derive(Debug, Error)] pub enum Introspection { + /// Config has no introspection url. #[error("Config has no introspection url")] NoUrl, + /// The Introspection Endpoint MUST return a `content-type` header to + /// indicate which format is being returned. #[error("The Introspection Endpoint MUST return a content-type header to indicate which format is being returned")] MissingContentType, + /// Not parsable content type header. #[error("Not parsable content type header: {content_type}")] - ParseContentType { content_type: String }, + ParseContentType { + /// Content type header value. + content_type: String, + }, + /// Wrong content type header. + /// + /// The following are accepted content types: `application/json`. #[error("Wrong content type header: {content_type}. The following are accepted content types: application/json")] - WrongContentType { content_type: String, body: Vec }, + WrongContentType { + /// Content type header value. + content_type: String, + /// Request body for analyze. + body: Vec, + }, } #[cfg(test)] diff --git a/src/lib.rs b/src/lib.rs index 2f367b8..945daa2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -32,6 +32,7 @@ mod standard_claims_subject; mod token; mod token_introspection; mod userinfo; +/// Token validation methods. pub mod validation; /// UMA2 OIDC/OAuth2 extension. @@ -65,7 +66,20 @@ pub mod biscuit { pub use biscuit::*; } +/// Alias for [Jws] pub type IdToken = Jws; +/// Alias for discovered [Client]. +/// +/// See also: +/// +/// - [Discovered] +/// - [StandardClaims] pub type DiscoveredClient = Client; +/// Alias for discovered UMA2 [Client] +/// +/// See also: +/// +/// - [uma2::DiscoveredUma2] +/// - [StandardClaims] #[cfg(feature = "uma2")] pub type DiscoveredUma2Client = Client; diff --git a/src/options.rs b/src/options.rs index b3d8728..0af8b0f 100644 --- a/src/options.rs +++ b/src/options.rs @@ -4,24 +4,116 @@ use chrono::Duration; use crate::{Display, Prompt}; -/// Optional parameters that [OpenID specifies](https://openid.net/specs/openid-connect-basic-1_0.html#RequestParameters) for the auth URI. +/// Optional request parameters. +/// +/// The request parameters that [OpenID specifies](https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest) for the auth URI. /// Derives Default, so remember to ..Default::default() after you specify what /// you want. -#[derive(Default)] +#[derive(Default, Debug)] pub struct Options { - /// MUST contain openid. By default this is ONLY openid. Official optional - /// scopes are email, profile, address, phone, offline_access. Check the - /// Discovery config `scopes_supported` to see what is available at your - /// provider! + /// REQUIRED. OpenID Connect requests MUST contain the `openid` scope value. + /// + /// If the `openid` scope value is not present, the behavior is entirely + /// unspecified. Other scope values MAY be present. Scope values used that + /// are not understood by an implementation SHOULD be ignored. See Sections + /// [5.4](https://openid.net/specs/openid-connect-core-1_0.html#ScopeClaims) and [11](https://openid.net/specs/openid-connect-core-1_0.html#OfflineAccess) for additional scope values defined by this + /// specification. pub scope: Option, + /// RECOMMENDED. Opaque value used to maintain state between the request and + /// the callback. + /// + /// Typically, Cross-Site Request Forgery (CSRF, XSRF) mitigation is done by + /// cryptographically binding the value of this parameter with a browser + /// cookie. pub state: Option, + /// OPTIONAL. String value used to associate a Client session with an ID + /// Token, and to mitigate replay attacks. + /// + /// The value is passed through unmodified from the Authentication Request + /// to the ID Token. Sufficient entropy MUST be present in the `nonce` + /// values used to prevent attackers from guessing values. For + /// implementation notes, see [Section 15.5.2](https://openid.net/specs/openid-connect-core-1_0.html#NonceNotes). pub nonce: Option, + /// OPTIONAL. ASCII string value that specifies how the Authorization Server + /// displays the authentication and consent user interface pages to the + /// End-User. pub display: Option, + /// OPTIONAL. Space-delimited, case-sensitive list of ASCII string values + /// that specifies whether the Authorization Server prompts the End-User for + /// reauthentication and consent. + /// + /// The `prompt` parameter can be used by the Client to make sure that the + /// End-User is still present for the current session or to bring attention + /// to the request. If this parameter contains none with any other value, an + /// error is returned. If an OP receives a `prompt` value outside the + /// set defined above that it does not understand, it MAY return an error or + /// it MAY ignore it; in practice, not returning errors for not-understood + /// values will help facilitate phasing in extensions using new `prompt` + /// values. pub prompt: Option>, + /// OPTIONAL. Maximum Authentication Age. + /// + /// Specifies the allowable elapsed time in seconds since the last time the + /// End-User was actively authenticated by the OP. If the elapsed time is + /// greater than this value, the OP MUST attempt to actively re-authenticate + /// the End-User. (The `max_age` request parameter corresponds to the OpenID + /// 2.0 PAPE [OpenID.PAPE](https://openid.net/specs/openid-connect-core-1_0.html#OpenID.PAPE) `max_auth_age` request parameter.) When `max_age` + /// is used, the ID Token returned MUST include an `auth_time` Claim Value. + /// Note that `max_age=0` is equivalent to `prompt=login`. pub max_age: Option, + /// OPTIONAL. End-User's preferred languages and scripts for the user + /// interface, represented as a space-separated list of BCP47 [RFC5646](https://openid.net/specs/openid-connect-core-1_0.html#RFC5646) + /// language tag values, ordered by preference. For instance, the value + /// "fr-CA fr en" represents a preference for French as spoken in Canada, + /// then French (without a region designation), followed by English (without + /// a region designation). An error SHOULD NOT result if some or all of the + /// requested locales are not supported by the OpenID Provider. pub ui_locales: Option, + /// OPTIONAL. End-User's preferred languages and scripts for Claims being + /// returned, represented as a space-separated list of BCP47 [RFC5646] + /// language tag values, ordered by preference. An error SHOULD NOT result + /// if some or all of the requested locales are not supported by the OpenID + /// Provider. pub claims_locales: Option, + /// OPTIONAL. ID Token previously issued by the Authorization Server being + /// passed as a hint about the End-User's current or past authenticated + /// session with the Client. + /// + /// If the End-User identified by the ID Token is already logged in or is + /// logged in as a result of the request (with the OP possibly evaluating + /// other information beyond the ID Token in this decision), then the + /// Authorization Server returns a positive response; otherwise, it MUST + /// return an error, such as `login_required`. When possible, an + /// `id_token_hint` SHOULD be present when `prompt=none` is used and an + /// invalid_request error MAY be returned if it is not; however, the server + /// SHOULD respond successfully when possible, even if it is not present. + /// The Authorization Server need not be listed as an audience of the ID + /// Token when it is used as an `id_token_hint` value. If the ID Token + /// received by the RP from the OP is encrypted, to use it as an + /// `id_token_hint`, the Client MUST decrypt the signed ID Token contained + /// within the encrypted ID Token. The Client MAY re-encrypt the signed ID + /// token to the Authentication Server using a key that enables the server + /// to decrypt the ID Token and use the re-encrypted ID token as the + /// `id_token_hint` value. pub id_token_hint: Option, + /// OPTIONAL. Hint to the Authorization Server about the login identifier + /// the End-User might use to log in (if necessary). + /// + /// This hint can be used by an RP if it first asks the End-User for their + /// e-mail address (or other identifier) and then wants to pass that value + /// as a hint to the discovered authorization service. It is RECOMMENDED + /// that the hint value match the value used for discovery. This value MAY + /// also be a phone number in the format specified for the phone_number + /// Claim. The use of this parameter is left to the OP's discretion. pub login_hint: Option, + /// OPTIONAL. Requested Authentication Context Class Reference values. + /// + /// Space-separated string that specifies the `acr` values that the + /// Authorization Server is being requested to use for processing this + /// Authentication Request, with the values appearing in order of + /// preference. The Authentication Context Class satisfied by the + /// authentication performed is returned as the `acr` Claim Value, as + /// specified in [Section 2](https://openid.net/specs/openid-connect-core-1_0.html#IDToken). The `acr` Claim is requested as a Voluntary + /// Claim by this parameter. pub acr_values: Option, } diff --git a/src/prompt.rs b/src/prompt.rs index f3ba1e6..6ae74aa 100644 --- a/src/prompt.rs +++ b/src/prompt.rs @@ -1,10 +1,33 @@ -/// The four possible values for the prompt parameter set in Options. See spec -/// for details. -#[derive(PartialEq, Eq, Hash)] +/// Authorization Server prompts. +/// +/// The four possible values for the prompt parameter set in Options. +/// +/// See [OpenID: 3.1.2.1. Authentication Request prompt](https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest) +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum Prompt { + /// The Authorization Server MUST NOT display any authentication or consent + /// user interface pages. An error is returned if an End-User is not already + /// authenticated or the Client does not have pre-configured consent for the + /// requested Claims or does not fulfill other conditions for processing the + /// request. The error code will typically be `login_required`, + /// `interaction_required`, or another code defined in [Section 3.1.2.6](https://openid.net/specs/openid-connect-core-1_0.html#AuthError). This + /// can be used as a method to check for existing authentication and/or + /// consent. None, + /// The Authorization Server SHOULD prompt the End-User for + /// reauthentication. If it cannot reauthenticate the End-User, it MUST + /// return an error, typically `login_required`. Login, + /// The Authorization Server SHOULD prompt the End-User for consent before + /// returning information to the Client. If it cannot obtain consent, it + /// MUST return an error, typically `consent_required`. Consent, + /// The Authorization Server SHOULD prompt the End-User to select a user + /// account. This enables an End-User who has multiple accounts at the + /// Authorization Server to select amongst the multiple accounts that they + /// might have current sessions for. If it cannot obtain an account + /// selection choice made by the End-User, it MUST return an error, + /// typically `account_selection_required`. SelectAccount, } diff --git a/src/standard_claims.rs b/src/standard_claims.rs index ffc02c3..9de8a77 100644 --- a/src/standard_claims.rs +++ b/src/standard_claims.rs @@ -4,14 +4,33 @@ use url::Url; use crate::{Claims, Userinfo}; -/// ID Token contents. [See spec.](https://openid.net/specs/openid-connect-basic-1_0.html#IDToken) +/// ID Token contents. [See spec.](https://openid.net/specs/openid-connect-core-1_0.html#IDToken) #[derive(Deserialize, Serialize, Debug, Clone, Eq, PartialEq)] pub struct StandardClaims { + /// Issuer Identifier for the Issuer of the response. + /// + /// The `iss` value is a case-sensitive URL using the `https` scheme that + /// contains scheme, host, and optionally, port number and path components + /// and no query or fragment components. pub iss: Url, // Max 255 ASCII chars // Can't deserialize a [u8; 255] + /// Subject Identifier. + /// + /// A locally unique and never reassigned identifier within the Issuer for + /// the End-User, which is intended to be consumed by the Client, e.g., + /// `24400320` or `AItOawmwtWwcT0k51BayewNvutrJUqsvl6qs7A4`. It MUST NOT + /// exceed 255 ASCII [RFC20] characters in length. The `sub` value is a + /// case-sensitive string. pub sub: String, // Either an array of audiences, or just the client_id + /// Audience(s) that this ID Token is intended for. + /// + /// It MUST contain the OAuth 2.0 `client_id` of the Relying Party as an + /// audience value. It MAY also contain identifiers for other audiences. In + /// the general case, the `aud` value is an array of case-sensitive strings. + /// In the common special case when there is one audience, the `aud` value + /// MAY be a single case-sensitive string. pub aud: SingleOrMultiple, // Not perfectly accurate for what time values we can get back... // By spec, this is an arbitrarilly large number. In practice, an @@ -19,26 +38,112 @@ pub struct StandardClaims { // // Make sure this cannot silently underflow, see: // https://github.com/serde-rs/json/blob/8e01f44f479b3ea96b299efc0da9131e7aff35dc/src/de.rs#L341 + /// Expiration time on or after which the ID Token MUST NOT be accepted by + /// the RP when performing authentication with the OP. + /// + /// The processing of this parameter requires that the current date/time + /// MUST be before the expiration date/time listed in the value. + /// Implementers MAY provide for some small leeway, usually no more than a + /// few minutes, to account for clock skew. Its value is a JSON [RFC8259] + /// number representing the number of seconds from `1970-01-01T00:00:00Z` as + /// measured in UTC until the date/time. See RFC 3339 [RFC3339] for details + /// regarding date/times in general and UTC in particular. NOTE: The ID + /// Token expiration time is unrelated the lifetime of the authenticated + /// session between the RP and the OP. pub exp: i64, + /// Time at which the JWT was issued. + /// + /// Its value is a JSON number representing the number of seconds from + /// `1970-01-01T00:00:00Z` as measured in UTC until the date/time. pub iat: i64, // required for max_age request + /// Time when the End-User authentication occurred. + /// + /// Its value is a JSON number representing the number of seconds from + /// `1970-01-01T00:00:00Z` as measured in UTC until the date/time. When a + /// `max_age` request is made or when `auth_time` is requested as an + /// Essential Claim, then this Claim is REQUIRED; otherwise, its inclusion + /// is OPTIONAL. (The `auth_time` Claim semantically corresponds to the + /// OpenID 2.0 PAPE [OpenID.PAPE] `auth_time` response parameter.) #[serde(default)] pub auth_time: Option, + /// String value used to associate a Client session with an ID Token, and to + /// mitigate replay attacks. + /// + /// The value is passed through unmodified from the Authentication Request + /// to the ID Token. If present in the ID Token, Clients MUST verify that + /// the `nonce` Claim Value is equal to the value of the `nonce` parameter + /// sent in the Authentication Request. If present in the Authentication + /// Request, Authorization Servers MUST include a `nonce` Claim in the ID + /// Token with the Claim Value being the `nonce` value sent in the + /// Authentication Request. Authorization Servers SHOULD perform no other + /// processing on `nonce` values used. The `nonce` value is a case-sensitive + /// string. #[serde(default)] pub nonce: Option, // base64 encoded, need to decode it! + /// Access Token hash value. Its value is the base64url encoding of the + /// left-most half of the hash of the octets of the ASCII representation of + /// the access_token value, where the hash algorithm used is the hash + /// algorithm used in the alg Header Parameter of the ID Token's JOSE + /// Header. For instance, if the alg is RS256, hash the access_token value + /// with SHA-256, then take the left-most 128 bits and base64url-encode + /// them. The at_hash value is a case-sensitive string. #[serde(default)] at_hash: Option, // base64 encoded, need to decode it! + /// Code hash value. Its value is the base64url encoding of the left-most + /// half of the hash of the octets of the ASCII representation of the code + /// value, where the hash algorithm used is the hash algorithm used in the + /// alg Header Parameter of the ID Token's JOSE Header. For instance, if the + /// alg is HS512, hash the code value with SHA-512, then take the left-most + /// 256 bits and base64url-encode them. The c_hash value is a case-sensitive + /// string. #[serde(default)] c_hash: Option, + /// Authentication Context Class Reference. + /// + /// String specifying an Authentication Context Class Reference value that + /// identifies the Authentication Context Class that the authentication + /// performed satisfied. The value "0" indicates the End-User authentication + /// did not meet the requirements of ISO/IEC 29115 [ISO29115] level 1. For + /// historic reasons, the value "0" is used to indicate that there is no + /// confidence that the same person is actually there. Authentications with + /// level 0 SHOULD NOT be used to authorize access to any resource of any + /// monetary value. (This corresponds to the OpenID 2.0 PAPE [OpenID.PAPE] + /// `nist_auth_level` 0.) An absolute URI or an RFC 6711 [RFC6711] + /// registered name SHOULD be used as the `acr` value; registered names MUST + /// NOT be used with a different meaning than that which is registered. + /// Parties using this claim will need to agree upon the meanings of the + /// values used, which may be context specific. The `acr` value is a + /// case-sensitive string. #[serde(default)] pub acr: Option, + /// Authentication Methods References. + /// + /// JSON array of strings that are identifiers for authentication methods + /// used in the authentication. For instance, values might indicate that + /// both password and OTP authentication methods were used. The `amr` value + /// is an array of case-sensitive strings. Values used in the `amr` Claim + /// SHOULD be from those registered in the IANA Authentication Method + /// Reference Values registry [IANA.AMR] established by [RFC8176]; parties + /// using this claim will need to agree upon the meanings of any + /// unregistered values used, which may be context specific. #[serde(default)] pub amr: Option>, // If exists, must be client_id + /// Authorized party - the party to which the ID Token was issued. If + /// present, it MUST contain the OAuth 2.0 Client ID of this party. The + /// `azp` value is a case-sensitive string containing a StringOrURI value. + /// Note that in practice, the `azp` Claim only occurs when extensions + /// beyond the scope of this specification are used; therefore, + /// implementations not using such extensions are encouraged to not use + /// `azp` and to ignore it when it does occur. #[serde(default)] pub azp: Option, + /// The standard claims. + /// + /// See [Standard Claims](https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims) #[serde(flatten)] pub userinfo: Userinfo, } diff --git a/src/standard_claims_subject.rs b/src/standard_claims_subject.rs index 4c6889e..d7f1cbe 100644 --- a/src/standard_claims_subject.rs +++ b/src/standard_claims_subject.rs @@ -1,9 +1,10 @@ use crate::error::StandardClaimsSubjectMissing; +/// Standard Claims: Subject. pub trait StandardClaimsSubject: crate::CompactJson { /// Subject - Identifier for the End-User at the Issuer. /// - /// See [Standard Claims](https://openid.net/specs/openid-connect-basic-1_0.html#StandardClaims) + /// See [Standard Claims](https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims) /// /// Errors: /// diff --git a/src/token.rs b/src/token.rs index 443f221..5bc0ff8 100644 --- a/src/token.rs +++ b/src/token.rs @@ -4,10 +4,17 @@ use biscuit::CompactJson; use crate::{Bearer, Claims, IdToken, StandardClaims}; /// An OpenID Connect token. This is the only token allowed by spec. -/// Has an access_token for bearer, and the id_token for authentication. +/// Has an `access_token` for bearer, and the `id_token` for authentication. /// Wraps an oauth bearer token. +#[allow(missing_debug_implementations)] pub struct Token { + /// Bearer Token. + /// + /// `access_token` pub bearer: Bearer, + /// ID Token + /// + /// `id_token` pub id_token: Option>, } diff --git a/src/userinfo.rs b/src/userinfo.rs index 50a1513..8f3c69d 100644 --- a/src/userinfo.rs +++ b/src/userinfo.rs @@ -6,7 +6,9 @@ use validator::Validate; use crate::{deserializers::bool_from_str_or_bool, Address, StandardClaimsSubject}; /// The userinfo struct contains all possible userinfo fields regardless of -/// scope. See: [OpenID Connect Core 1.0: Standard Claims](https://openid.net/specs/openid-connect-basic-1_0.html#StandardClaims) +/// scope. +/// +/// See: [OpenID Connect Core 1.0: Standard Claims](https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims) #[derive(Debug, Deserialize, Serialize, Validate, Clone, Eq, PartialEq)] pub struct Userinfo { #[serde(default)] diff --git a/src/validation.rs b/src/validation.rs index be8d034..9d2c31e 100644 --- a/src/validation.rs +++ b/src/validation.rs @@ -6,6 +6,7 @@ use crate::{ Claims, Config, }; +/// Validate token issuer. pub fn validate_token_issuer(claims: &C, config: &Config) -> Result<(), Error> { if claims.iss() != &config.issuer { let expected = config.issuer.as_str().to_string(); @@ -16,6 +17,7 @@ pub fn validate_token_issuer(claims: &C, config: &Config) -> Result<( Ok(()) } +/// Validate token nonce. pub fn validate_token_nonce<'nonce, C: Claims>( claims: &C, nonce: impl Into>, @@ -36,6 +38,7 @@ pub fn validate_token_nonce<'nonce, C: Claims>( Ok(()) } +/// Validate token aud. pub fn validate_token_aud(claims: &C, client_id: &str) -> Result<(), Error> { if !claims.aud().contains(client_id) { return Err(Validation::Missing(Missing::Audience).into()); @@ -60,6 +63,7 @@ pub fn validate_token_aud(claims: &C, client_id: &str) -> Result<(), Ok(()) } +/// Validate token expiration against current time. pub fn validate_token_exp<'max_age, C: Claims>( claims: &C, max_age: impl Into>, diff --git a/templates/README.md b/templates/README.md index 461c049..9bfa023 100644 --- a/templates/README.md +++ b/templates/README.md @@ -62,6 +62,6 @@ in Cargo.toml: in src/main.rs: -{{ codeblock "rust, ignore" ( http_get (replace "https://raw.githubusercontent.com/kilork/openid-examples/vVERSION/examples/warp.rs" "VERSION" (env_var "OPENID_RUST_MAJOR_VERSION") ) ) }} +{{ codeblock "rust, no_run" ( http_get (replace "https://raw.githubusercontent.com/kilork/openid-examples/vVERSION/examples/warp.rs" "VERSION" (env_var "OPENID_RUST_MAJOR_VERSION") ) ) }} See full example: [openid-examples: warp](https://github.com/kilork/openid-examples/blob/v{{ env_var "OPENID_RUST_MAJOR_VERSION" }}/examples/warp.rs)