1
0
mirror of https://github.com/matrix-org/matrix-authentication-service.git synced 2025-08-06 06:02:40 +03:00

Replace parse-display with manual Display/FromStr impls

This commit is contained in:
Quentin Gliech
2024-03-19 15:05:50 +01:00
parent 4eeedbef31
commit 7e30daf83e
10 changed files with 334 additions and 168 deletions

49
Cargo.lock generated
View File

@@ -3869,7 +3869,6 @@ dependencies = [
"language-tags", "language-tags",
"mas-iana", "mas-iana",
"mas-jose", "mas-jose",
"parse-display",
"serde", "serde",
"serde_json", "serde_json",
"serde_with", "serde_with",
@@ -4156,31 +4155,6 @@ dependencies = [
"windows-targets 0.48.5", "windows-targets 0.48.5",
] ]
[[package]]
name = "parse-display"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06af5f9333eb47bd9ba8462d612e37a8328a5cb80b13f0af4de4c3b89f52dee5"
dependencies = [
"parse-display-derive",
"regex",
"regex-syntax 0.8.2",
]
[[package]]
name = "parse-display-derive"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc9252f259500ee570c75adcc4e317fa6f57a1e47747d622e0bf838002a7b790"
dependencies = [
"proc-macro2",
"quote",
"regex",
"regex-syntax 0.8.2",
"structmeta",
"syn 2.0.53",
]
[[package]] [[package]]
name = "parse-size" name = "parse-size"
version = "1.0.0" version = "1.0.0"
@@ -5857,29 +5831,6 @@ version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01" checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01"
[[package]]
name = "structmeta"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2e1575d8d40908d70f6fd05537266b90ae71b15dbbe7a8b7dffa2b759306d329"
dependencies = [
"proc-macro2",
"quote",
"structmeta-derive",
"syn 2.0.53",
]
[[package]]
name = "structmeta-derive"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "152a0b65a590ff6c3da95cabe2353ee04e6167c896b28e3b14478c2636c922fc"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.53",
]
[[package]] [[package]]
name = "strum" name = "strum"
version = "0.25.0" version = "0.25.0"

View File

@@ -197,9 +197,10 @@ impl OAuth2Client {
/// The application type advertised by the client. /// The application type advertised by the client.
pub async fn application_type(&self) -> Option<OAuth2ApplicationType> { pub async fn application_type(&self) -> Option<OAuth2ApplicationType> {
match self.0.application_type? { match self.0.application_type.as_ref()? {
ApplicationType::Web => Some(OAuth2ApplicationType::Web), ApplicationType::Web => Some(OAuth2ApplicationType::Web),
ApplicationType::Native => Some(OAuth2ApplicationType::Native), ApplicationType::Native => Some(OAuth2ApplicationType::Native),
ApplicationType::Unknown(_) => None,
} }
} }
} }

View File

@@ -268,7 +268,7 @@ pub(crate) async fn post(
&clock, &clock,
metadata.redirect_uris().to_vec(), metadata.redirect_uris().to_vec(),
encrypted_client_secret, encrypted_client_secret,
metadata.application_type, metadata.application_type.clone(),
//&metadata.response_types(), //&metadata.response_types(),
metadata.grant_types().to_vec(), metadata.grant_types().to_vec(),
metadata.contacts.clone().unwrap_or_default(), metadata.contacts.clone().unwrap_or_default(),

View File

@@ -17,7 +17,6 @@ serde.workspace = true
serde_json.workspace = true serde_json.workspace = true
language-tags = { version = "0.3.2", features = ["serde"] } language-tags = { version = "0.3.2", features = ["serde"] }
url.workspace = true url.workspace = true
parse-display = "0.9.0"
serde_with = { version = "3.7.0", features = ["chrono"] } serde_with = { version = "3.7.0", features = ["chrono"] }
chrono.workspace = true chrono.workspace = true
sha2 = "0.10.8" sha2 = "0.10.8"

View File

@@ -16,7 +16,6 @@
use std::borrow::Cow; use std::borrow::Cow;
use parse_display::{Display, FromStr};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use serde_with::{DeserializeFromStr, SerializeDisplay}; use serde_with::{DeserializeFromStr, SerializeDisplay};
@@ -60,8 +59,7 @@ impl From<ClientErrorCode> for ClientError {
} }
/// Client error codes defined in OAuth2.0, OpenID Connect and their extensions. /// Client error codes defined in OAuth2.0, OpenID Connect and their extensions.
#[derive(Debug, Clone, PartialEq, Eq, Display, FromStr, SerializeDisplay, DeserializeFromStr)] #[derive(Debug, Clone, PartialEq, Eq, SerializeDisplay, DeserializeFromStr)]
#[display(style = "snake_case")]
pub enum ClientErrorCode { pub enum ClientErrorCode {
/// `invalid_request` /// `invalid_request`
/// ///
@@ -276,10 +274,77 @@ pub enum ClientErrorCode {
UnsupportedTokenType, UnsupportedTokenType,
/// Another error code. /// Another error code.
#[display("{0}")]
Unknown(String), Unknown(String),
} }
impl core::fmt::Display for ClientErrorCode {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
ClientErrorCode::InvalidRequest => f.write_str("invalid_request"),
ClientErrorCode::InvalidClient => f.write_str("invalid_client"),
ClientErrorCode::InvalidGrant => f.write_str("invalid_grant"),
ClientErrorCode::UnauthorizedClient => f.write_str("unauthorized_client"),
ClientErrorCode::UnsupportedGrantType => f.write_str("unsupported_grant_type"),
ClientErrorCode::AccessDenied => f.write_str("access_denied"),
ClientErrorCode::UnsupportedResponseType => f.write_str("unsupported_response_type"),
ClientErrorCode::InvalidScope => f.write_str("invalid_scope"),
ClientErrorCode::ServerError => f.write_str("server_error"),
ClientErrorCode::TemporarilyUnavailable => f.write_str("temporarily_unavailable"),
ClientErrorCode::InteractionRequired => f.write_str("interaction_required"),
ClientErrorCode::LoginRequired => f.write_str("login_required"),
ClientErrorCode::AccountSelectionRequired => f.write_str("account_selection_required"),
ClientErrorCode::ConsentRequired => f.write_str("consent_required"),
ClientErrorCode::InvalidRequestUri => f.write_str("invalid_request_uri"),
ClientErrorCode::InvalidRequestObject => f.write_str("invalid_request_object"),
ClientErrorCode::RequestNotSupported => f.write_str("request_not_supported"),
ClientErrorCode::RequestUriNotSupported => f.write_str("request_uri_not_supported"),
ClientErrorCode::RegistrationNotSupported => f.write_str("registration_not_supported"),
ClientErrorCode::InvalidRedirectUri => f.write_str("invalid_redirect_uri"),
ClientErrorCode::InvalidClientMetadata => f.write_str("invalid_client_metadata"),
ClientErrorCode::AuthorizationPending => f.write_str("authorization_pending"),
ClientErrorCode::SlowDown => f.write_str("slow_down"),
ClientErrorCode::ExpiredToken => f.write_str("expired_token"),
ClientErrorCode::UnsupportedTokenType => f.write_str("unsupported_token_type"),
ClientErrorCode::Unknown(value) => f.write_str(value),
}
}
}
impl core::str::FromStr for ClientErrorCode {
type Err = core::convert::Infallible;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"invalid_request" => Ok(ClientErrorCode::InvalidRequest),
"invalid_client" => Ok(ClientErrorCode::InvalidClient),
"invalid_grant" => Ok(ClientErrorCode::InvalidGrant),
"unauthorized_client" => Ok(ClientErrorCode::UnauthorizedClient),
"unsupported_grant_type" => Ok(ClientErrorCode::UnsupportedGrantType),
"access_denied" => Ok(ClientErrorCode::AccessDenied),
"unsupported_response_type" => Ok(ClientErrorCode::UnsupportedResponseType),
"invalid_scope" => Ok(ClientErrorCode::InvalidScope),
"server_error" => Ok(ClientErrorCode::ServerError),
"temporarily_unavailable" => Ok(ClientErrorCode::TemporarilyUnavailable),
"interaction_required" => Ok(ClientErrorCode::InteractionRequired),
"login_required" => Ok(ClientErrorCode::LoginRequired),
"account_selection_required" => Ok(ClientErrorCode::AccountSelectionRequired),
"consent_required" => Ok(ClientErrorCode::ConsentRequired),
"invalid_request_uri" => Ok(ClientErrorCode::InvalidRequestUri),
"invalid_request_object" => Ok(ClientErrorCode::InvalidRequestObject),
"request_not_supported" => Ok(ClientErrorCode::RequestNotSupported),
"request_uri_not_supported" => Ok(ClientErrorCode::RequestUriNotSupported),
"registration_not_supported" => Ok(ClientErrorCode::RegistrationNotSupported),
"invalid_redirect_uri" => Ok(ClientErrorCode::InvalidRedirectUri),
"invalid_client_metadata" => Ok(ClientErrorCode::InvalidClientMetadata),
"authorization_pending" => Ok(ClientErrorCode::AuthorizationPending),
"slow_down" => Ok(ClientErrorCode::SlowDown),
"expired_token" => Ok(ClientErrorCode::ExpiredToken),
"unsupported_token_type" => Ok(ClientErrorCode::UnsupportedTokenType),
_ => Ok(ClientErrorCode::Unknown(s.to_owned())),
}
}
}
impl ClientErrorCode { impl ClientErrorCode {
/// Get the default description for this `ClientErrorCode`. /// Get the default description for this `ClientErrorCode`.
/// ///

View File

@@ -16,14 +16,13 @@
//! //!
//! [OpenID Connect]: https://openid.net/connect/ //! [OpenID Connect]: https://openid.net/connect/
use std::{fmt, ops::Deref, str::FromStr}; use std::{fmt, ops::Deref};
use language_tags::LanguageTag; use language_tags::LanguageTag;
use mas_iana::{ use mas_iana::{
jose::{JsonWebEncryptionAlg, JsonWebEncryptionEnc, JsonWebSignatureAlg}, jose::{JsonWebEncryptionAlg, JsonWebEncryptionEnc, JsonWebSignatureAlg},
oauth::{OAuthAccessTokenType, OAuthClientAuthenticationMethod, PkceCodeChallengeMethod}, oauth::{OAuthAccessTokenType, OAuthClientAuthenticationMethod, PkceCodeChallengeMethod},
}; };
use parse_display::{Display, FromStr, ParseError};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use serde_with::{ use serde_with::{
formats::SpaceSeparator, serde_as, skip_serializing_none, DeserializeFromStr, SerializeDisplay, formats::SpaceSeparator, serde_as, skip_serializing_none, DeserializeFromStr, SerializeDisplay,
@@ -39,14 +38,12 @@ use crate::{
/// An enum for types that accept either an [`OAuthClientAuthenticationMethod`] /// An enum for types that accept either an [`OAuthClientAuthenticationMethod`]
/// or an [`OAuthAccessTokenType`]. /// or an [`OAuthAccessTokenType`].
#[derive(SerializeDisplay, DeserializeFromStr, Clone, PartialEq, Eq, Hash, Debug, Display)] #[derive(SerializeDisplay, DeserializeFromStr, Clone, PartialEq, Eq, Hash, Debug)]
pub enum AuthenticationMethodOrAccessTokenType { pub enum AuthenticationMethodOrAccessTokenType {
/// An authentication method. /// An authentication method.
#[display("{0}")]
AuthenticationMethod(OAuthClientAuthenticationMethod), AuthenticationMethod(OAuthClientAuthenticationMethod),
/// An access token type. /// An access token type.
#[display("{0}")]
AccessTokenType(OAuthAccessTokenType), AccessTokenType(OAuthAccessTokenType),
/// An unknown value. /// An unknown value.
@@ -54,10 +51,37 @@ pub enum AuthenticationMethodOrAccessTokenType {
/// Note that this variant should only be used as the result parsing a /// Note that this variant should only be used as the result parsing a
/// string of unknown type. To build a custom variant, first parse a /// string of unknown type. To build a custom variant, first parse a
/// string with the wanted type then use `.into()`. /// string with the wanted type then use `.into()`.
#[display("{0}")]
Unknown(String), Unknown(String),
} }
impl core::fmt::Display for AuthenticationMethodOrAccessTokenType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::AuthenticationMethod(m) => m.fmt(f),
Self::AccessTokenType(t) => t.fmt(f),
Self::Unknown(s) => s.fmt(f),
}
}
}
impl core::str::FromStr for AuthenticationMethodOrAccessTokenType {
type Err = core::convert::Infallible;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match OAuthClientAuthenticationMethod::from_str(s) {
Ok(OAuthClientAuthenticationMethod::Unknown(_)) | Err(_) => {}
Ok(m) => return Ok(m.into()),
}
match OAuthAccessTokenType::from_str(s) {
Ok(OAuthAccessTokenType::Unknown(_)) | Err(_) => {}
Ok(m) => return Ok(m.into()),
}
Ok(Self::Unknown(s.to_owned()))
}
}
impl AuthenticationMethodOrAccessTokenType { impl AuthenticationMethodOrAccessTokenType {
/// Get the authentication method of this /// Get the authentication method of this
/// `AuthenticationMethodOrAccessTokenType`. /// `AuthenticationMethodOrAccessTokenType`.
@@ -80,28 +104,6 @@ impl AuthenticationMethodOrAccessTokenType {
} }
} }
impl FromStr for AuthenticationMethodOrAccessTokenType {
type Err = ParseError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
if let Ok(m) = OAuthClientAuthenticationMethod::from_str(s) {
match m {
OAuthClientAuthenticationMethod::Unknown(_) => {}
m => return Ok(m.into()),
}
}
if let Ok(t) = OAuthAccessTokenType::from_str(s) {
match t {
OAuthAccessTokenType::Unknown(_) => {}
t => return Ok(t.into()),
}
}
Ok(Self::Unknown(s.to_owned()))
}
}
impl From<OAuthClientAuthenticationMethod> for AuthenticationMethodOrAccessTokenType { impl From<OAuthClientAuthenticationMethod> for AuthenticationMethodOrAccessTokenType {
fn from(t: OAuthClientAuthenticationMethod) -> Self { fn from(t: OAuthClientAuthenticationMethod) -> Self {
Self::AuthenticationMethod(t) Self::AuthenticationMethod(t)
@@ -115,16 +117,38 @@ impl From<OAuthAccessTokenType> for AuthenticationMethodOrAccessTokenType {
} }
/// The kind of an application. /// The kind of an application.
#[derive( #[derive(SerializeDisplay, DeserializeFromStr, Clone, PartialEq, Eq, Hash, Debug)]
SerializeDisplay, DeserializeFromStr, Clone, Copy, PartialEq, Eq, Hash, Debug, Display, FromStr,
)]
#[display(style = "lowercase")]
pub enum ApplicationType { pub enum ApplicationType {
/// A web application. /// A web application.
Web, Web,
/// A native application. /// A native application.
Native, Native,
/// An unknown value.
Unknown(String),
}
impl core::fmt::Display for ApplicationType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Web => f.write_str("web"),
Self::Native => f.write_str("native"),
Self::Unknown(s) => f.write_str(s),
}
}
}
impl core::str::FromStr for ApplicationType {
type Err = core::convert::Infallible;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"web" => Ok(Self::Web),
"native" => Ok(Self::Native),
s => Ok(Self::Unknown(s.to_owned())),
}
}
} }
/// Subject Identifier types. /// Subject Identifier types.
@@ -132,10 +156,7 @@ pub enum ApplicationType {
/// A Subject Identifier is a locally unique and never reassigned identifier /// 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 /// within the Issuer for the End-User, which is intended to be consumed by the
/// Client. /// Client.
#[derive( #[derive(SerializeDisplay, DeserializeFromStr, Clone, PartialEq, Eq, Hash, Debug)]
SerializeDisplay, DeserializeFromStr, Clone, Copy, PartialEq, Eq, Hash, Debug, Display, FromStr,
)]
#[display(style = "lowercase")]
pub enum SubjectType { pub enum SubjectType {
/// This provides the same `sub` (subject) value to all Clients. /// This provides the same `sub` (subject) value to all Clients.
Public, Public,
@@ -144,13 +165,35 @@ pub enum SubjectType {
/// enable Clients to correlate the End-User's activities without /// enable Clients to correlate the End-User's activities without
/// permission. /// permission.
Pairwise, Pairwise,
/// An unknown value.
Unknown(String),
}
impl core::fmt::Display for SubjectType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Public => f.write_str("public"),
Self::Pairwise => f.write_str("pairwise"),
Self::Unknown(s) => f.write_str(s),
}
}
}
impl core::str::FromStr for SubjectType {
type Err = core::convert::Infallible;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"public" => Ok(Self::Public),
"pairwise" => Ok(Self::Pairwise),
s => Ok(Self::Unknown(s.to_owned())),
}
}
} }
/// Claim types. /// Claim types.
#[derive( #[derive(SerializeDisplay, DeserializeFromStr, Clone, PartialEq, Eq, Hash, Debug)]
SerializeDisplay, DeserializeFromStr, Clone, Copy, PartialEq, Eq, Hash, Debug, Display, FromStr,
)]
#[display(style = "lowercase")]
pub enum ClaimType { pub enum ClaimType {
/// Claims that are directly asserted by the OpenID Provider. /// Claims that are directly asserted by the OpenID Provider.
Normal, Normal,
@@ -162,6 +205,33 @@ pub enum ClaimType {
/// Claims that are asserted by a Claims Provider other than the OpenID /// Claims that are asserted by a Claims Provider other than the OpenID
/// Provider but are returned as references by the OpenID Provider. /// Provider but are returned as references by the OpenID Provider.
Distributed, Distributed,
/// An unknown value.
Unknown(String),
}
impl core::fmt::Display for ClaimType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Normal => f.write_str("normal"),
Self::Aggregated => f.write_str("aggregated"),
Self::Distributed => f.write_str("distributed"),
Self::Unknown(s) => f.write_str(s),
}
}
}
impl core::str::FromStr for ClaimType {
type Err = core::convert::Infallible;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"normal" => Ok(Self::Normal),
"aggregated" => Ok(Self::Aggregated),
"distributed" => Ok(Self::Distributed),
s => Ok(Self::Unknown(s.to_owned())),
}
}
} }
/// An account management action that a user can take. /// An account management action that a user can take.

View File

@@ -613,7 +613,9 @@ impl ClientMetadata {
/// Defaults to [`DEFAULT_APPLICATION_TYPE`]. /// Defaults to [`DEFAULT_APPLICATION_TYPE`].
#[must_use] #[must_use]
pub fn application_type(&self) -> ApplicationType { pub fn application_type(&self) -> ApplicationType {
self.application_type.unwrap_or(DEFAULT_APPLICATION_TYPE) self.application_type
.clone()
.unwrap_or(DEFAULT_APPLICATION_TYPE)
} }
/// Requested client authentication method for the [token endpoint]. /// Requested client authentication method for the [token endpoint].

View File

@@ -21,7 +21,6 @@ use std::{collections::HashSet, fmt, hash::Hash, num::NonZeroU32};
use chrono::{DateTime, Duration, Utc}; use chrono::{DateTime, Duration, Utc};
use language_tags::LanguageTag; use language_tags::LanguageTag;
use mas_iana::oauth::{OAuthAccessTokenType, OAuthTokenTypeHint}; use mas_iana::oauth::{OAuthAccessTokenType, OAuthTokenTypeHint};
use parse_display::{Display, FromStr};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use serde_with::{ use serde_with::{
formats::SpaceSeparator, serde_as, skip_serializing_none, DeserializeFromStr, DisplayFromStr, formats::SpaceSeparator, serde_as, skip_serializing_none, DeserializeFromStr, DisplayFromStr,
@@ -38,19 +37,8 @@ use crate::{response_type::ResponseType, scope::Scope};
/// ///
/// Defined in [OAuth 2.0 Multiple Response Type Encoding Practices](https://openid.net/specs/oauth-v2-multiple-response-types-1_0.html#ResponseModes). /// Defined in [OAuth 2.0 Multiple Response Type Encoding Practices](https://openid.net/specs/oauth-v2-multiple-response-types-1_0.html#ResponseModes).
#[derive( #[derive(
Debug, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Clone, SerializeDisplay, DeserializeFromStr,
Hash,
PartialEq,
Eq,
PartialOrd,
Ord,
Clone,
Display,
FromStr,
SerializeDisplay,
DeserializeFromStr,
)] )]
#[display(style = "snake_case")]
#[non_exhaustive] #[non_exhaustive]
pub enum ResponseMode { pub enum ResponseMode {
/// Authorization Response parameters are encoded in the query string added /// Authorization Response parameters are encoded in the query string added
@@ -71,28 +59,40 @@ pub enum ResponseMode {
FormPost, FormPost,
/// An unknown value. /// An unknown value.
#[display("{0}")]
Unknown(String), Unknown(String),
} }
impl core::fmt::Display for ResponseMode {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
ResponseMode::Query => f.write_str("query"),
ResponseMode::Fragment => f.write_str("fragment"),
ResponseMode::FormPost => f.write_str("form_post"),
ResponseMode::Unknown(s) => f.write_str(s),
}
}
}
impl core::str::FromStr for ResponseMode {
type Err = core::convert::Infallible;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"query" => Ok(ResponseMode::Query),
"fragment" => Ok(ResponseMode::Fragment),
"form_post" => Ok(ResponseMode::FormPost),
s => Ok(ResponseMode::Unknown(s.to_owned())),
}
}
}
/// Value that specifies how the Authorization Server displays the /// Value that specifies how the Authorization Server displays the
/// authentication and consent user interface pages to the End-User. /// authentication and consent user interface pages to the End-User.
/// ///
/// Defined in [OpenID Connect Core 1.0](https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest). /// Defined in [OpenID Connect Core 1.0](https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest).
#[derive( #[derive(
Debug, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Clone, SerializeDisplay, DeserializeFromStr,
Hash,
PartialEq,
Eq,
PartialOrd,
Ord,
Clone,
Display,
FromStr,
SerializeDisplay,
DeserializeFromStr,
)] )]
#[display(style = "snake_case")]
#[non_exhaustive] #[non_exhaustive]
pub enum Display { pub enum Display {
/// The Authorization Server should display the authentication and consent /// The Authorization Server should display the authentication and consent
@@ -114,10 +114,35 @@ pub enum Display {
Wap, Wap,
/// An unknown value. /// An unknown value.
#[display("{0}")]
Unknown(String), Unknown(String),
} }
impl core::fmt::Display for Display {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
Display::Page => f.write_str("page"),
Display::Popup => f.write_str("popup"),
Display::Touch => f.write_str("touch"),
Display::Wap => f.write_str("wap"),
Display::Unknown(s) => f.write_str(s),
}
}
}
impl core::str::FromStr for Display {
type Err = core::convert::Infallible;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"page" => Ok(Display::Page),
"popup" => Ok(Display::Popup),
"touch" => Ok(Display::Touch),
"wap" => Ok(Display::Wap),
s => Ok(Display::Unknown(s.to_owned())),
}
}
}
impl Default for Display { impl Default for Display {
fn default() -> Self { fn default() -> Self {
Self::Page Self::Page
@@ -129,19 +154,8 @@ impl Default for Display {
/// ///
/// Defined in [OpenID Connect Core 1.0](https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest). /// Defined in [OpenID Connect Core 1.0](https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest).
#[derive( #[derive(
Debug, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Clone, SerializeDisplay, DeserializeFromStr,
Hash,
PartialEq,
Eq,
PartialOrd,
Ord,
Clone,
Display,
FromStr,
SerializeDisplay,
DeserializeFromStr,
)] )]
#[display(style = "snake_case")]
#[non_exhaustive] #[non_exhaustive]
pub enum Prompt { pub enum Prompt {
/// The Authorization Server must not display any authentication or consent /// The Authorization Server must not display any authentication or consent
@@ -171,10 +185,37 @@ pub enum Prompt {
Create, Create,
/// An unknown value. /// An unknown value.
#[display("{0}")]
Unknown(String), Unknown(String),
} }
impl core::fmt::Display for Prompt {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
Prompt::None => f.write_str("none"),
Prompt::Login => f.write_str("login"),
Prompt::Consent => f.write_str("consent"),
Prompt::SelectAccount => f.write_str("select_account"),
Prompt::Create => f.write_str("create"),
Prompt::Unknown(s) => f.write_str(s),
}
}
}
impl core::str::FromStr for Prompt {
type Err = core::convert::Infallible;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"none" => Ok(Prompt::None),
"login" => Ok(Prompt::Login),
"consent" => Ok(Prompt::Consent),
"select_account" => Ok(Prompt::SelectAccount),
"create" => Ok(Prompt::Create),
s => Ok(Prompt::Unknown(s.to_owned())),
}
}
}
/// The body of a request to the [Authorization Endpoint]. /// The body of a request to the [Authorization Endpoint].
/// ///
/// [Authorization Endpoint]: https://www.rfc-editor.org/rfc/rfc6749.html#section-3.1 /// [Authorization Endpoint]: https://www.rfc-editor.org/rfc/rfc6749.html#section-3.1
@@ -511,20 +552,8 @@ impl fmt::Debug for DeviceCodeGrant {
/// All possible values for the `grant_type` parameter. /// All possible values for the `grant_type` parameter.
#[derive( #[derive(
Debug, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Clone, SerializeDisplay, DeserializeFromStr,
Hash,
PartialEq,
Eq,
PartialOrd,
Ord,
Clone,
Copy,
Display,
FromStr,
SerializeDisplay,
DeserializeFromStr,
)] )]
#[display(style = "snake_case")]
pub enum GrantType { pub enum GrantType {
/// [`authorization_code`](https://www.rfc-editor.org/rfc/rfc6749#section-4.1) /// [`authorization_code`](https://www.rfc-editor.org/rfc/rfc6749#section-4.1)
AuthorizationCode, AuthorizationCode,
@@ -542,16 +571,54 @@ pub enum GrantType {
Password, Password,
/// [`urn:ietf:params:oauth:grant-type:device_code`](https://www.rfc-editor.org/rfc/rfc8628) /// [`urn:ietf:params:oauth:grant-type:device_code`](https://www.rfc-editor.org/rfc/rfc8628)
#[display("urn:ietf:params:oauth:grant-type:device_code")]
DeviceCode, DeviceCode,
/// [`https://datatracker.ietf.org/doc/html/rfc7523#section-2.1`](https://www.rfc-editor.org/rfc/rfc7523#section-2.1) /// [`https://datatracker.ietf.org/doc/html/rfc7523#section-2.1`](https://www.rfc-editor.org/rfc/rfc7523#section-2.1)
#[display("urn:ietf:params:oauth:grant-type:jwt-bearer")]
JwtBearer, JwtBearer,
/// [`urn:openid:params:grant-type:ciba`](https://openid.net/specs/openid-client-initiated-backchannel-authentication-core-1_0.html) /// [`urn:openid:params:grant-type:ciba`](https://openid.net/specs/openid-client-initiated-backchannel-authentication-core-1_0.html)
#[display("urn:openid:params:grant-type:ciba")]
ClientInitiatedBackchannelAuthentication, ClientInitiatedBackchannelAuthentication,
/// An unknown value.
Unknown(String),
}
impl core::fmt::Display for GrantType {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
GrantType::AuthorizationCode => f.write_str("authorization_code"),
GrantType::RefreshToken => f.write_str("refresh_token"),
GrantType::Implicit => f.write_str("implicit"),
GrantType::ClientCredentials => f.write_str("client_credentials"),
GrantType::Password => f.write_str("password"),
GrantType::DeviceCode => f.write_str("urn:ietf:params:oauth:grant-type:device_code"),
GrantType::JwtBearer => f.write_str("urn:ietf:params:oauth:grant-type:jwt-bearer"),
GrantType::ClientInitiatedBackchannelAuthentication => {
f.write_str("urn:openid:params:grant-type:ciba")
}
GrantType::Unknown(s) => f.write_str(s),
}
}
}
impl core::str::FromStr for GrantType {
type Err = core::convert::Infallible;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"authorization_code" => Ok(GrantType::AuthorizationCode),
"refresh_token" => Ok(GrantType::RefreshToken),
"implicit" => Ok(GrantType::Implicit),
"client_credentials" => Ok(GrantType::ClientCredentials),
"password" => Ok(GrantType::Password),
"urn:ietf:params:oauth:grant-type:device_code" => Ok(GrantType::DeviceCode),
"urn:ietf:params:oauth:grant-type:jwt-bearer" => Ok(GrantType::JwtBearer),
"urn:openid:params:grant-type:ciba" => {
Ok(GrantType::ClientInitiatedBackchannelAuthentication)
}
s => Ok(GrantType::Unknown(s.to_owned())),
}
}
} }
/// An enum representing the possible requests to the [Token Endpoint]. /// An enum representing the possible requests to the [Token Endpoint].

View File

@@ -21,7 +21,6 @@
use std::{collections::BTreeSet, fmt, iter::FromIterator, str::FromStr}; use std::{collections::BTreeSet, fmt, iter::FromIterator, str::FromStr};
use mas_iana::oauth::OAuthAuthorizationEndpointResponseType; use mas_iana::oauth::OAuthAuthorizationEndpointResponseType;
use parse_display::{Display, FromStr};
use serde_with::{DeserializeFromStr, SerializeDisplay}; use serde_with::{DeserializeFromStr, SerializeDisplay};
use thiserror::Error; use thiserror::Error;
@@ -38,19 +37,8 @@ pub struct InvalidResponseType;
/// This type also accepts unknown tokens that can be constructed via it's /// This type also accepts unknown tokens that can be constructed via it's
/// `FromStr` implementation or used via its `Display` implementation. /// `FromStr` implementation or used via its `Display` implementation.
#[derive( #[derive(
Debug, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, SerializeDisplay, DeserializeFromStr,
Clone,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
Display,
FromStr,
SerializeDisplay,
DeserializeFromStr,
)] )]
#[display(style = "snake_case")]
#[non_exhaustive] #[non_exhaustive]
pub enum ResponseTypeToken { pub enum ResponseTypeToken {
/// `code` /// `code`
@@ -63,10 +51,33 @@ pub enum ResponseTypeToken {
Token, Token,
/// Unknown token. /// Unknown token.
#[display("{0}")]
Unknown(String), Unknown(String),
} }
impl core::fmt::Display for ResponseTypeToken {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
ResponseTypeToken::Code => f.write_str("code"),
ResponseTypeToken::IdToken => f.write_str("id_token"),
ResponseTypeToken::Token => f.write_str("token"),
ResponseTypeToken::Unknown(s) => f.write_str(s),
}
}
}
impl core::str::FromStr for ResponseTypeToken {
type Err = core::convert::Infallible;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"code" => Ok(Self::Code),
"id_token" => Ok(Self::IdToken),
"token" => Ok(Self::Token),
s => Ok(Self::Unknown(s.to_owned())),
}
}
}
/// An [OAuth 2.0 `response_type` value] that the client can use /// An [OAuth 2.0 `response_type` value] that the client can use
/// at the [authorization endpoint]. /// at the [authorization endpoint].
/// ///

View File

@@ -463,7 +463,7 @@ impl<'c> OAuth2ClientRepository for PgOAuth2ClientRepository<'c> {
"#, "#,
Uuid::from(id), Uuid::from(id),
encrypted_client_secret, encrypted_client_secret,
application_type.map(|a| a.to_string()), application_type.as_ref().map(ToString::to_string),
&redirect_uris_array, &redirect_uris_array,
grant_types.contains(&GrantType::AuthorizationCode), grant_types.contains(&GrantType::AuthorizationCode),
grant_types.contains(&GrantType::RefreshToken), grant_types.contains(&GrantType::RefreshToken),