You've already forked authentication-service
mirror of
https://github.com/matrix-org/matrix-authentication-service.git
synced 2025-07-29 22:01:14 +03:00
Use iana generated types in more places
This commit is contained in:
@ -16,11 +16,46 @@
|
||||
#![deny(clippy::all)]
|
||||
#![warn(clippy::pedantic)]
|
||||
|
||||
use mas_iana::oauth::OAuthAuthorizationEndpointResponseType;
|
||||
|
||||
pub trait ResponseTypeExt {
|
||||
fn has_code(&self) -> bool;
|
||||
fn has_token(&self) -> bool;
|
||||
fn has_id_token(&self) -> bool;
|
||||
}
|
||||
|
||||
impl ResponseTypeExt for OAuthAuthorizationEndpointResponseType {
|
||||
fn has_code(&self) -> bool {
|
||||
matches!(
|
||||
self,
|
||||
Self::Code | Self::CodeToken | Self::CodeIdToken | Self::CodeIdTokenToken
|
||||
)
|
||||
}
|
||||
|
||||
fn has_token(&self) -> bool {
|
||||
matches!(
|
||||
self,
|
||||
Self::Token | Self::CodeToken | Self::IdTokenToken | Self::CodeIdTokenToken
|
||||
)
|
||||
}
|
||||
|
||||
fn has_id_token(&self) -> bool {
|
||||
matches!(
|
||||
self,
|
||||
Self::IdToken | Self::IdTokenToken | Self::CodeIdToken | Self::CodeIdTokenToken
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub mod errors;
|
||||
pub mod oidc;
|
||||
pub mod pkce;
|
||||
pub mod requests;
|
||||
pub mod scope;
|
||||
|
||||
pub mod prelude {
|
||||
pub use crate::{pkce::CodeChallengeMethodExt, ResponseTypeExt};
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test_utils;
|
||||
|
@ -14,15 +14,18 @@
|
||||
|
||||
use std::collections::HashSet;
|
||||
|
||||
use mas_iana::jose::{JsonWebEncryptionAlg, JsonWebEncryptionEnc, JsonWebSignatureAlg};
|
||||
use mas_iana::{
|
||||
jose::{JsonWebEncryptionAlg, JsonWebEncryptionEnc, JsonWebSignatureAlg},
|
||||
oauth::{
|
||||
OAuthAuthorizationEndpointResponseType, OAuthClientAuthenticationMethod,
|
||||
PkceCodeChallengeMethod,
|
||||
},
|
||||
};
|
||||
use serde::Serialize;
|
||||
use serde_with::skip_serializing_none;
|
||||
use url::Url;
|
||||
|
||||
use crate::{
|
||||
pkce::CodeChallengeMethod,
|
||||
requests::{ClientAuthenticationMethod, Display, GrantType, ResponseMode},
|
||||
};
|
||||
use crate::requests::{Display, GrantType, ResponseMode};
|
||||
|
||||
#[derive(Serialize, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
@ -66,7 +69,7 @@ pub struct Metadata {
|
||||
|
||||
/// JSON array containing a list of the OAuth 2.0 "response_type" values
|
||||
/// that this authorization server supports.
|
||||
pub response_types_supported: Option<HashSet<String>>,
|
||||
pub response_types_supported: Option<HashSet<OAuthAuthorizationEndpointResponseType>>,
|
||||
|
||||
/// JSON array containing a list of the OAuth 2.0 "response_mode" values
|
||||
/// that this authorization server supports.
|
||||
@ -78,7 +81,7 @@ pub struct Metadata {
|
||||
|
||||
/// JSON array containing a list of client authentication methods supported
|
||||
/// by this token endpoint.
|
||||
pub token_endpoint_auth_methods_supported: Option<HashSet<ClientAuthenticationMethod>>,
|
||||
pub token_endpoint_auth_methods_supported: Option<HashSet<OAuthClientAuthenticationMethod>>,
|
||||
|
||||
/// JSON array containing a list of the JWS signing algorithms supported by
|
||||
/// the token endpoint for the signature on the JWT used to authenticate the
|
||||
@ -109,7 +112,8 @@ pub struct Metadata {
|
||||
|
||||
/// JSON array containing a list of client authentication methods supported
|
||||
/// by this revocation endpoint.
|
||||
pub revocation_endpoint_auth_methods_supported: Option<HashSet<ClientAuthenticationMethod>>,
|
||||
pub revocation_endpoint_auth_methods_supported:
|
||||
Option<HashSet<OAuthClientAuthenticationMethod>>,
|
||||
|
||||
/// JSON array containing a list of the JWS signing algorithms supported by
|
||||
/// the revocation endpoint for the signature on the JWT used to
|
||||
@ -121,7 +125,8 @@ pub struct Metadata {
|
||||
|
||||
/// JSON array containing a list of client authentication methods supported
|
||||
/// by this introspection endpoint.
|
||||
pub introspection_endpoint_auth_methods_supported: Option<HashSet<ClientAuthenticationMethod>>,
|
||||
pub introspection_endpoint_auth_methods_supported:
|
||||
Option<HashSet<OAuthClientAuthenticationMethod>>,
|
||||
|
||||
/// JSON array containing a list of the JWS signing algorithms supported by
|
||||
/// the introspection endpoint for the signature on the JWT used to
|
||||
@ -130,7 +135,7 @@ pub struct Metadata {
|
||||
Option<HashSet<JsonWebSignatureAlg>>,
|
||||
|
||||
/// PKCE code challenge methods supported by this authorization server.
|
||||
pub code_challenge_methods_supported: Option<HashSet<CodeChallengeMethod>>,
|
||||
pub code_challenge_methods_supported: Option<HashSet<PkceCodeChallengeMethod>>,
|
||||
|
||||
/// URL of the OP's UserInfo Endpoint.
|
||||
pub userinfo_endpoint: Option<Url>,
|
||||
|
@ -15,40 +15,23 @@
|
||||
use std::borrow::Cow;
|
||||
|
||||
use data_encoding::BASE64URL_NOPAD;
|
||||
use parse_display::{Display, FromStr};
|
||||
use mas_iana::oauth::PkceCodeChallengeMethod;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sha2::{Digest, Sha256};
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
Hash,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
Clone,
|
||||
Copy,
|
||||
Display,
|
||||
FromStr,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
)]
|
||||
pub enum CodeChallengeMethod {
|
||||
#[serde(rename = "plain")]
|
||||
#[display("plain")]
|
||||
Plain,
|
||||
pub trait CodeChallengeMethodExt {
|
||||
#[must_use]
|
||||
fn compute_challenge(self, verifier: &str) -> Cow<'_, str>;
|
||||
|
||||
#[serde(rename = "S256")]
|
||||
#[display("S256")]
|
||||
S256,
|
||||
#[must_use]
|
||||
fn verify(self, challenge: &str, verifier: &str) -> bool;
|
||||
}
|
||||
|
||||
impl CodeChallengeMethod {
|
||||
#[must_use]
|
||||
pub fn compute_challenge(self, verifier: &str) -> Cow<'_, str> {
|
||||
impl CodeChallengeMethodExt for PkceCodeChallengeMethod {
|
||||
fn compute_challenge(self, verifier: &str) -> Cow<'_, str> {
|
||||
match self {
|
||||
CodeChallengeMethod::Plain => verifier.into(),
|
||||
CodeChallengeMethod::S256 => {
|
||||
Self::Plain => verifier.into(),
|
||||
Self::S256 => {
|
||||
let mut hasher = Sha256::new();
|
||||
hasher.update(verifier.as_bytes());
|
||||
let hash = hasher.finalize();
|
||||
@ -58,15 +41,14 @@ impl CodeChallengeMethod {
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn verify(self, challenge: &str, verifier: &str) -> bool {
|
||||
fn verify(self, challenge: &str, verifier: &str) -> bool {
|
||||
self.compute_challenge(verifier) == challenge
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct AuthorizationRequest {
|
||||
pub code_challenge_method: CodeChallengeMethod,
|
||||
pub code_challenge_method: PkceCodeChallengeMethod,
|
||||
pub code_challenge: String,
|
||||
}
|
||||
|
||||
|
@ -16,6 +16,9 @@ use std::{collections::HashSet, hash::Hash, num::NonZeroU32};
|
||||
|
||||
use chrono::{DateTime, Duration, Utc};
|
||||
use language_tags::LanguageTag;
|
||||
use mas_iana::oauth::{
|
||||
OAuthAccessTokenType, OAuthAuthorizationEndpointResponseType, OAuthTokenTypeHint,
|
||||
};
|
||||
use parse_display::{Display, FromStr};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_with::{
|
||||
@ -28,29 +31,6 @@ use crate::scope::Scope;
|
||||
|
||||
// ref: https://www.iana.org/assignments/oauth-parameters/oauth-parameters.xhtml
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
Hash,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
Clone,
|
||||
Copy,
|
||||
Display,
|
||||
FromStr,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
)]
|
||||
#[display(style = "snake_case")]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum ResponseType {
|
||||
Code,
|
||||
IdToken,
|
||||
Token,
|
||||
None,
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
Hash,
|
||||
@ -72,37 +52,6 @@ pub enum ResponseMode {
|
||||
FormPost,
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
Hash,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
Clone,
|
||||
Copy,
|
||||
Display,
|
||||
FromStr,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum ClientAuthenticationMethod {
|
||||
None,
|
||||
ClientSecretPost,
|
||||
ClientSecretBasic,
|
||||
ClientSecretJwt,
|
||||
PrivateKeyJwt,
|
||||
}
|
||||
|
||||
impl ClientAuthenticationMethod {
|
||||
#[must_use]
|
||||
/// Check if the authentication method is for public client or not
|
||||
pub fn public(&self) -> bool {
|
||||
matches!(self, &Self::None)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
Hash,
|
||||
@ -151,8 +100,7 @@ pub enum Prompt {
|
||||
#[serde_as]
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct AuthorizationRequest {
|
||||
#[serde_as(as = "StringWithSeparator::<SpaceSeparator, ResponseType>")]
|
||||
pub response_type: HashSet<ResponseType>,
|
||||
pub response_type: OAuthAuthorizationEndpointResponseType,
|
||||
|
||||
pub client_id: String,
|
||||
|
||||
@ -200,25 +148,6 @@ pub struct AuthorizationResponse<R> {
|
||||
pub response: R,
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
Hash,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
Clone,
|
||||
Copy,
|
||||
Display,
|
||||
FromStr,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum TokenType {
|
||||
Bearer,
|
||||
}
|
||||
|
||||
#[skip_serializing_none]
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq)]
|
||||
pub struct AuthorizationCodeGrant {
|
||||
@ -285,7 +214,7 @@ pub struct AccessTokenResponse {
|
||||
// TODO: this should be somewhere else
|
||||
id_token: Option<String>,
|
||||
|
||||
token_type: TokenType,
|
||||
token_type: OAuthAccessTokenType,
|
||||
|
||||
#[serde_as(as = "Option<DurationSeconds<i64>>")]
|
||||
expires_in: Option<Duration>,
|
||||
@ -300,7 +229,7 @@ impl AccessTokenResponse {
|
||||
access_token,
|
||||
refresh_token: None,
|
||||
id_token: None,
|
||||
token_type: TokenType::Bearer,
|
||||
token_type: OAuthAccessTokenType::Bearer,
|
||||
expires_in: None,
|
||||
scope: None,
|
||||
}
|
||||
@ -331,20 +260,13 @@ impl AccessTokenResponse {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum TokenTypeHint {
|
||||
AccessToken,
|
||||
RefreshToken,
|
||||
}
|
||||
|
||||
#[skip_serializing_none]
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq)]
|
||||
pub struct IntrospectionRequest {
|
||||
pub token: String,
|
||||
|
||||
#[serde(default)]
|
||||
pub token_type_hint: Option<TokenTypeHint>,
|
||||
pub token_type_hint: Option<OAuthTokenTypeHint>,
|
||||
}
|
||||
|
||||
#[serde_as]
|
||||
@ -359,7 +281,7 @@ pub struct IntrospectionResponse {
|
||||
|
||||
pub username: Option<String>,
|
||||
|
||||
pub token_type: Option<TokenTypeHint>,
|
||||
pub token_type: Option<OAuthTokenTypeHint>,
|
||||
|
||||
#[serde_as(as = "Option<TimestampSeconds>")]
|
||||
pub exp: Option<DateTime<Utc>>,
|
||||
|
Reference in New Issue
Block a user