You've already forked authentication-service
mirror of
https://github.com/matrix-org/matrix-authentication-service.git
synced 2025-07-28 11:02:02 +03:00
Make sure all types of oauth2-types are documented
This commit is contained in:
committed by
Quentin Gliech
parent
c02f59bbaf
commit
66055b044e
@ -12,6 +12,8 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//! Error types returned by an authorization server.
|
||||
|
||||
use std::borrow::Cow;
|
||||
|
||||
use parse_display::{Display, FromStr};
|
||||
@ -56,6 +58,7 @@ impl From<ClientErrorCode> for ClientError {
|
||||
}
|
||||
}
|
||||
|
||||
/// Client error codes defined in OAuth2.0, OpenID Connect and their extensions.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Display, FromStr, SerializeDisplay, DeserializeFromStr)]
|
||||
#[display(style = "snake_case")]
|
||||
pub enum ClientErrorCode {
|
||||
|
@ -12,8 +12,21 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//! [OAuth 2.0] and [OpenID Connect] types.
|
||||
//!
|
||||
//! This is part of the [Matrix Authentication Service] project.
|
||||
//!
|
||||
//! [OAuth 2.0]: https://oauth.net/2/
|
||||
//! [OpenID Connect]: https://openid.net/connect/
|
||||
//! [Matrix Authentication Service]: https://github.com/matrix-org/matrix-authentication-service
|
||||
|
||||
#![forbid(unsafe_code)]
|
||||
#![deny(clippy::all, clippy::str_to_string, rustdoc::broken_intra_doc_links)]
|
||||
#![deny(
|
||||
clippy::all,
|
||||
clippy::str_to_string,
|
||||
rustdoc::broken_intra_doc_links,
|
||||
missing_docs
|
||||
)]
|
||||
#![warn(clippy::pedantic)]
|
||||
#![allow(clippy::module_name_repetitions)]
|
||||
|
||||
@ -26,6 +39,7 @@ pub mod response_type;
|
||||
pub mod scope;
|
||||
pub mod webfinger;
|
||||
|
||||
/// Traits intended for blanket imports.
|
||||
pub mod prelude {
|
||||
pub use crate::pkce::CodeChallengeMethodExt;
|
||||
}
|
||||
|
@ -12,6 +12,10 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//! Types to interact with the [OpenID Connect] specification.
|
||||
//!
|
||||
//! [OpenID Connect]: https://openid.net/connect/
|
||||
|
||||
use std::{ops::Deref, str::FromStr};
|
||||
|
||||
use language_tags::LanguageTag;
|
||||
@ -107,43 +111,63 @@ impl From<OAuthAccessTokenType> for AuthenticationMethodOrAccessTokenType {
|
||||
}
|
||||
}
|
||||
|
||||
/// The kind of an application.
|
||||
#[derive(
|
||||
SerializeDisplay, DeserializeFromStr, Clone, Copy, PartialEq, Eq, Hash, Debug, Display, FromStr,
|
||||
)]
|
||||
#[display(style = "lowercase")]
|
||||
pub enum ApplicationType {
|
||||
/// A web application.
|
||||
Web,
|
||||
|
||||
/// A native application.
|
||||
Native,
|
||||
}
|
||||
|
||||
/// Subject Identifier types.
|
||||
///
|
||||
/// A Subject Identifier is a locally unique and never reassigned identifier within the Issuer for the End-User, which is intended to be consumed by the Client.
|
||||
#[derive(
|
||||
SerializeDisplay, DeserializeFromStr, Clone, Copy, PartialEq, Eq, Hash, Debug, Display, FromStr,
|
||||
)]
|
||||
#[display(style = "lowercase")]
|
||||
pub enum SubjectType {
|
||||
/// This provides the same `sub` (subject) value to all Clients.
|
||||
Public,
|
||||
|
||||
/// This provides a different `sub` value to each Client, so as not to enable Clients to correlate the End-User's activities without permission.
|
||||
Pairwise,
|
||||
}
|
||||
|
||||
/// Claim types.
|
||||
#[derive(
|
||||
SerializeDisplay, DeserializeFromStr, Clone, Copy, PartialEq, Eq, Hash, Debug, Display, FromStr,
|
||||
)]
|
||||
#[display(style = "lowercase")]
|
||||
pub enum ClaimType {
|
||||
/// Claims that are directly asserted by the OpenID Provider.
|
||||
Normal,
|
||||
|
||||
/// Claims that are asserted by a Claims Provider other than the OpenID Provider but are returned by OpenID Provider.
|
||||
Aggregated,
|
||||
|
||||
/// Claims that are asserted by a Claims Provider other than the OpenID Provider but are returned as references by the OpenID Provider.
|
||||
Distributed,
|
||||
}
|
||||
|
||||
/// The default value of `response_modes_supported` if it is not set.
|
||||
pub static DEFAULT_RESPONSE_MODES_SUPPORTED: &[ResponseMode] =
|
||||
&[ResponseMode::Query, ResponseMode::Fragment];
|
||||
|
||||
/// The default value of `grant_types_supported` if it is not set.
|
||||
pub static DEFAULT_GRANT_TYPES_SUPPORTED: &[GrantType] =
|
||||
&[GrantType::AuthorizationCode, GrantType::Implicit];
|
||||
|
||||
/// The default value of `token_endpoint_auth_methods_supported` if it is not set.
|
||||
pub static DEFAULT_AUTH_METHODS_SUPPORTED: &[OAuthClientAuthenticationMethod] =
|
||||
&[OAuthClientAuthenticationMethod::ClientSecretBasic];
|
||||
|
||||
/// The default value of `claim_types_supported` if it is not set.
|
||||
pub static DEFAULT_CLAIM_TYPES_SUPPORTED: &[ClaimType] = &[ClaimType::Normal];
|
||||
|
||||
/// Authorization server metadata, as described by the [IANA registry].
|
||||
|
@ -12,6 +12,10 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//! Types for the [Proof Key for Code Exchange].
|
||||
//!
|
||||
//! [Proof Key for Code Exchange]: https://www.rfc-editor.org/rfc/rfc7636
|
||||
|
||||
use std::borrow::Cow;
|
||||
|
||||
use data_encoding::BASE64URL_NOPAD;
|
||||
@ -20,20 +24,26 @@ use serde::{Deserialize, Serialize};
|
||||
use sha2::{Digest, Sha256};
|
||||
use thiserror::Error;
|
||||
|
||||
/// Errors that can occur when verifying a code challenge.
|
||||
#[derive(Debug, Error, PartialEq, Eq)]
|
||||
pub enum CodeChallengeError {
|
||||
/// The code verifier should be at least 43 characters long.
|
||||
#[error("code_verifier should be at least 43 characters long")]
|
||||
TooShort,
|
||||
|
||||
/// The code verifier should be at most 128 characters long.
|
||||
#[error("code_verifier should be at most 128 characters long")]
|
||||
TooLong,
|
||||
|
||||
/// The code verifier contains invalid characters.
|
||||
#[error("code_verifier contains invalid characters")]
|
||||
InvalidCharacters,
|
||||
|
||||
/// The challenge verification failed.
|
||||
#[error("challenge verification failed")]
|
||||
VerificationFailed,
|
||||
|
||||
/// The challenge method is unsupported.
|
||||
#[error("unknown challenge method")]
|
||||
UnknownChallengeMethod,
|
||||
}
|
||||
@ -57,6 +67,7 @@ fn validate_verifier(verifier: &str) -> Result<(), CodeChallengeError> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Helper trait to compute and verify code challenges.
|
||||
pub trait CodeChallengeMethodExt {
|
||||
/// Compute the challenge for a given verifier
|
||||
///
|
||||
@ -105,14 +116,20 @@ impl CodeChallengeMethodExt for PkceCodeChallengeMethod {
|
||||
}
|
||||
}
|
||||
|
||||
/// The code challenge data added to an authorization request.
|
||||
#[derive(Clone, Serialize, Deserialize)]
|
||||
pub struct AuthorizationRequest {
|
||||
/// The code challenge method.
|
||||
pub code_challenge_method: PkceCodeChallengeMethod,
|
||||
|
||||
/// The code challenge computed from the verifier and the method.
|
||||
pub code_challenge: String,
|
||||
}
|
||||
|
||||
/// The code challenge data added to a token request.
|
||||
#[derive(Clone, Serialize, Deserialize)]
|
||||
pub struct TokenRequest {
|
||||
/// The code challenge verifier.
|
||||
pub code_challenge_verifier: String,
|
||||
}
|
||||
|
||||
|
@ -12,6 +12,10 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//! Types for [Dynamic Client Registration].
|
||||
//!
|
||||
//! [Dynamic Client Registration]: https://openid.net/specs/openid-connect-registration-1_0.html
|
||||
|
||||
use std::{collections::HashMap, ops::Deref};
|
||||
|
||||
use chrono::{DateTime, Duration, Utc};
|
||||
@ -35,18 +39,24 @@ use crate::{
|
||||
mod client_metadata_serde;
|
||||
use client_metadata_serde::ClientMetadataSerdeHelper;
|
||||
|
||||
/// The default value of `response_types` if it is not set.
|
||||
pub const DEFAULT_RESPONSE_TYPES: [OAuthAuthorizationEndpointResponseType; 1] =
|
||||
[OAuthAuthorizationEndpointResponseType::Code];
|
||||
|
||||
/// The default value of `grant_types` if it is not set.
|
||||
pub const DEFAULT_GRANT_TYPES: &[GrantType] = &[GrantType::AuthorizationCode];
|
||||
|
||||
/// The default value of `application_type` if it is not set.
|
||||
pub const DEFAULT_APPLICATION_TYPE: ApplicationType = ApplicationType::Web;
|
||||
|
||||
/// The default value of `token_endpoint_auth_method` if it is not set.
|
||||
pub const DEFAULT_TOKEN_AUTH_METHOD: &OAuthClientAuthenticationMethod =
|
||||
&OAuthClientAuthenticationMethod::ClientSecretBasic;
|
||||
|
||||
/// The default value of `id_token_signed_response_alg` if it is not set.
|
||||
pub const DEFAULT_SIGNING_ALGORITHM: &JsonWebSignatureAlg = &JsonWebSignatureAlg::Rs256;
|
||||
|
||||
/// The default value of `id_token_encrypted_response_enc` if it is not set.
|
||||
pub const DEFAULT_ENCRYPTION_ENC_ALGORITHM: &JsonWebEncryptionEnc =
|
||||
&JsonWebEncryptionEnc::A128CbcHs256;
|
||||
|
||||
@ -841,19 +851,26 @@ pub enum ClientMetadataVerificationError {
|
||||
MissingEncryptionAlg(&'static str),
|
||||
}
|
||||
|
||||
/// The issuer response to dynamic client registration.
|
||||
#[serde_as]
|
||||
#[skip_serializing_none]
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
|
||||
pub struct ClientRegistrationResponse {
|
||||
/// A unique client identifier.
|
||||
pub client_id: String,
|
||||
|
||||
/// A client secret, if the `token_endpoint_auth_method` requires one.
|
||||
#[serde(default)]
|
||||
pub client_secret: Option<String>,
|
||||
|
||||
/// Time at which the Client Identifier was issued.
|
||||
#[serde(default)]
|
||||
#[serde_as(as = "Option<TimestampSeconds<i64>>")]
|
||||
pub client_id_issued_at: Option<DateTime<Utc>>,
|
||||
|
||||
/// Time at which the client_secret will expire or 0 if it will not expire.
|
||||
///
|
||||
/// Required if `client_secret` is issued.
|
||||
#[serde(default)]
|
||||
#[serde_as(as = "Option<TimestampSeconds<i64>>")]
|
||||
pub client_secret_expires_at: Option<DateTime<Utc>>,
|
||||
|
@ -12,6 +12,10 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//! Requests and response types to interact with the [OAuth 2.0] specification.
|
||||
//!
|
||||
//! [OAuth 2.0]: https://oauth.net/2/
|
||||
|
||||
use std::{collections::HashSet, fmt, hash::Hash, num::NonZeroU32};
|
||||
|
||||
use chrono::{DateTime, Duration, Utc};
|
||||
@ -323,7 +327,10 @@ impl fmt::Debug for AuthorizationRequest {
|
||||
#[skip_serializing_none]
|
||||
#[derive(Serialize, Deserialize, Default, Clone)]
|
||||
pub struct AuthorizationResponse<R> {
|
||||
/// The authorization code generated by the authorization server.
|
||||
pub code: Option<String>,
|
||||
|
||||
/// Other fields of the response.
|
||||
#[serde(flatten)]
|
||||
pub response: R,
|
||||
}
|
||||
@ -345,6 +352,7 @@ pub struct DeviceAuthorizationRequest {
|
||||
pub scope: Option<Scope>,
|
||||
}
|
||||
|
||||
/// The default value of the `interval` between polling requests, if it is not set.
|
||||
pub const DEFAULT_DEVICE_AUTHORIZATION_INTERVAL_SECONDS: i64 = 5;
|
||||
|
||||
/// A successful response from the [Device Authorization Endpoint].
|
||||
@ -384,7 +392,7 @@ pub struct DeviceAuthorizationResponse {
|
||||
}
|
||||
|
||||
impl DeviceAuthorizationResponse {
|
||||
///The minimum amount of time in seconds that the client should wait
|
||||
/// The minimum amount of time in seconds that the client should wait
|
||||
/// between polling requests to the token endpoint.
|
||||
///
|
||||
/// Defaults to [`DEFAULT_DEVICE_AUTHORIZATION_INTERVAL_SECONDS`].
|
||||
@ -535,11 +543,20 @@ pub enum GrantType {
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
|
||||
#[serde(tag = "grant_type", rename_all = "snake_case")]
|
||||
pub enum AccessTokenRequest {
|
||||
/// A request in the Authorization Code flow.
|
||||
AuthorizationCode(AuthorizationCodeGrant),
|
||||
|
||||
/// A request to refresh an access token.
|
||||
RefreshToken(RefreshTokenGrant),
|
||||
|
||||
/// A request in the Client Credentials flow.
|
||||
ClientCredentials(ClientCredentialsGrant),
|
||||
|
||||
/// A request in the Device Code flow.
|
||||
#[serde(rename = "urn:ietf:params:oauth:grant-type:device_code")]
|
||||
DeviceCode(DeviceCodeGrant),
|
||||
|
||||
/// An unsupported request.
|
||||
#[serde(skip, other)]
|
||||
Unsupported,
|
||||
}
|
||||
|
@ -12,6 +12,10 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//! [Response types] in the OpenID Connect specification.
|
||||
//!
|
||||
//! [Response types]: https://openid.net/specs/openid-connect-core-1_0.html#Authentication
|
||||
|
||||
#![allow(clippy::module_name_repetitions)]
|
||||
|
||||
use std::{collections::BTreeSet, fmt, iter::FromIterator, str::FromStr};
|
||||
|
@ -12,6 +12,10 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//! Types to define an [access token's scope].
|
||||
//!
|
||||
//! [access token's scope]: https://www.rfc-editor.org/rfc/rfc6749#section-3.3
|
||||
|
||||
#![allow(clippy::module_name_repetitions)]
|
||||
|
||||
use std::{borrow::Cow, collections::BTreeSet, iter::FromIterator, ops::Deref, str::FromStr};
|
||||
@ -20,10 +24,12 @@ use itertools::Itertools;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use thiserror::Error;
|
||||
|
||||
/// The error type returned when a scope is invalid.
|
||||
#[derive(Debug, Error, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
#[error("Invalid scope format")]
|
||||
pub struct InvalidScope;
|
||||
|
||||
/// A scope token or scope value.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct ScopeToken(Cow<'static, str>);
|
||||
|
||||
@ -36,11 +42,34 @@ impl ScopeToken {
|
||||
}
|
||||
}
|
||||
|
||||
/// `openid`.
|
||||
///
|
||||
/// Must be included in OpenID Connect requests.
|
||||
pub const OPENID: ScopeToken = ScopeToken::from_static("openid");
|
||||
|
||||
/// `profile`.
|
||||
///
|
||||
/// Requests access to the End-User's default profile Claims.
|
||||
pub const PROFILE: ScopeToken = ScopeToken::from_static("profile");
|
||||
|
||||
/// `email`.
|
||||
///
|
||||
/// Requests access to the `email` and `email_verified` Claims.
|
||||
pub const EMAIL: ScopeToken = ScopeToken::from_static("email");
|
||||
|
||||
/// `address`.
|
||||
///
|
||||
/// Requests access to the `address` Claim.
|
||||
pub const ADDRESS: ScopeToken = ScopeToken::from_static("address");
|
||||
|
||||
/// `phone`.
|
||||
///
|
||||
/// Requests access to the `phone_number` and `phone_number_verified` Claims.
|
||||
pub const PHONE: ScopeToken = ScopeToken::from_static("phone");
|
||||
|
||||
/// `offline_access`.
|
||||
///
|
||||
/// Requests that an OAuth 2.0 Refresh Token be issued that can be used to obtain an Access Token that grants access to the End-User's Userinfo Endpoint even when the End-User is not present (not logged in).
|
||||
pub const OFFLINE_ACCESS: ScopeToken = ScopeToken::from_static("offline_access");
|
||||
|
||||
// As per RFC6749 appendix A:
|
||||
@ -81,6 +110,7 @@ impl ToString for ScopeToken {
|
||||
}
|
||||
}
|
||||
|
||||
/// A scope.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct Scope(BTreeSet<ScopeToken>);
|
||||
|
||||
@ -108,17 +138,20 @@ impl FromStr for Scope {
|
||||
}
|
||||
|
||||
impl Scope {
|
||||
/// Whether this `Scope` is empty.
|
||||
#[must_use]
|
||||
pub fn is_empty(&self) -> bool {
|
||||
// This should never be the case?
|
||||
self.0.is_empty()
|
||||
}
|
||||
|
||||
/// The number of tokens in the `Scope`.
|
||||
#[must_use]
|
||||
pub fn len(&self) -> usize {
|
||||
self.0.len()
|
||||
}
|
||||
|
||||
/// Whether this `Scope` contains the given value.
|
||||
#[must_use]
|
||||
pub fn contains(&self, token: &str) -> bool {
|
||||
ScopeToken::from_str(token)
|
||||
@ -126,6 +159,9 @@ impl Scope {
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
/// Inserts the given token in this `Scope`.
|
||||
///
|
||||
/// Returns whether the token was newly inserted.
|
||||
pub fn insert(&mut self, value: ScopeToken) -> bool {
|
||||
self.0.insert(value)
|
||||
}
|
||||
|
@ -12,16 +12,25 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//! Types for provider discovery using [Webfinger].
|
||||
//!
|
||||
//! [Webfinger]: https://www.rfc-editor.org/rfc/rfc7033
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use url::Url;
|
||||
|
||||
/// The response of the Webfinger endpoint.
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
|
||||
pub struct WebFingerResponse {
|
||||
/// A URI that identifies the entity described by the response.
|
||||
subject: String,
|
||||
|
||||
/// Links that describe the subject.
|
||||
links: Vec<WebFingerLink>,
|
||||
}
|
||||
|
||||
impl WebFingerResponse {
|
||||
/// Creates a new `WebFingerResponse` with the given subject.
|
||||
#[must_use]
|
||||
pub const fn new(subject: String) -> Self {
|
||||
Self {
|
||||
@ -30,26 +39,34 @@ impl WebFingerResponse {
|
||||
}
|
||||
}
|
||||
|
||||
/// Adds the given link to this `WebFingerResponse`.
|
||||
#[must_use]
|
||||
pub fn with_link(mut self, link: WebFingerLink) -> Self {
|
||||
self.links.push(link);
|
||||
self
|
||||
}
|
||||
|
||||
/// Adds the given issuer to this `WebFingerResponse`.
|
||||
#[must_use]
|
||||
pub fn with_issuer(self, issuer: Url) -> Self {
|
||||
self.with_link(WebFingerLink::issuer(issuer))
|
||||
}
|
||||
}
|
||||
|
||||
/// A link in a Webfinger response.
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
|
||||
#[serde(tag = "rel")]
|
||||
pub enum WebFingerLink {
|
||||
/// An OpenID Connect issuer.
|
||||
#[serde(rename = "http://openid.net/specs/connect/1.0/issuer")]
|
||||
OidcIssuer { href: Url },
|
||||
OidcIssuer {
|
||||
/// The URL of the issuer.
|
||||
href: Url,
|
||||
},
|
||||
}
|
||||
|
||||
impl WebFingerLink {
|
||||
/// Creates a new `WebFingerLink` for an OpenID Connect issuer.
|
||||
#[must_use]
|
||||
pub const fn issuer(href: Url) -> Self {
|
||||
Self::OidcIssuer { href }
|
||||
|
Reference in New Issue
Block a user