1
0
mirror of https://github.com/matrix-org/matrix-authentication-service.git synced 2025-07-28 11:02:02 +03:00

Add variants for unknown values on mas-iana types

Remove the Copy derive and mark enums as non-exhaustive.
This commit is contained in:
Kévin Commaille
2022-09-13 18:32:56 +02:00
committed by Quentin Gliech
parent 9e3b3567b2
commit 80d317f23c
25 changed files with 414 additions and 292 deletions

2
Cargo.lock generated
View File

@ -2519,7 +2519,7 @@ version = "0.1.0"
dependencies = [ dependencies = [
"parse-display", "parse-display",
"schemars", "schemars",
"serde", "serde_with",
] ]
[[package]] [[package]]

View File

@ -92,7 +92,7 @@ impl Credentials {
pub async fn verify<S: StorageBackend>( pub async fn verify<S: StorageBackend>(
&self, &self,
encrypter: &Encrypter, encrypter: &Encrypter,
method: OAuthClientAuthenticationMethod, method: &OAuthClientAuthenticationMethod,
client: &Client<S>, client: &Client<S>,
) -> Result<(), CredentialsVerificationError> { ) -> Result<(), CredentialsVerificationError> {
match (self, method) { match (self, method) {

View File

@ -162,7 +162,7 @@ pub(crate) async fn post(
let client = client_authorization.credentials.fetch(&mut conn).await?; let client = client_authorization.credentials.fetch(&mut conn).await?;
let method = match client.token_endpoint_auth_method { let method = match &client.token_endpoint_auth_method {
None | Some(OAuthClientAuthenticationMethod::None) => { None | Some(OAuthClientAuthenticationMethod::None) => {
return Err(RouteError::NotAllowed); return Err(RouteError::NotAllowed);
} }

View File

@ -151,10 +151,10 @@ pub(crate) async fn post(
metadata.tos_uri.as_ref().map(Localized::non_localized), metadata.tos_uri.as_ref().map(Localized::non_localized),
metadata.jwks_uri.as_ref(), metadata.jwks_uri.as_ref(),
metadata.jwks.as_ref(), metadata.jwks.as_ref(),
metadata.id_token_signed_response_alg, metadata.id_token_signed_response_alg.as_ref(),
metadata.userinfo_signed_response_alg, metadata.userinfo_signed_response_alg.as_ref(),
metadata.token_endpoint_auth_method, metadata.token_endpoint_auth_method.as_ref(),
metadata.token_endpoint_auth_signing_alg, metadata.token_endpoint_auth_signing_alg.as_ref(),
metadata.initiate_login_uri.as_ref(), metadata.initiate_login_uri.as_ref(),
) )
.await?; .await?;

View File

@ -198,6 +198,7 @@ pub(crate) async fn post(
let method = client let method = client
.token_endpoint_auth_method .token_endpoint_auth_method
.as_ref()
.ok_or(RouteError::ClientNotAllowed)?; .ok_or(RouteError::ClientNotAllowed)?;
client_authorization client_authorization
@ -333,17 +334,18 @@ async fn authorization_code_grant(
let alg = client let alg = client
.id_token_signed_response_alg .id_token_signed_response_alg
.clone()
.unwrap_or(JsonWebSignatureAlg::Rs256); .unwrap_or(JsonWebSignatureAlg::Rs256);
let key = key_store let key = key_store
.signing_key_for_algorithm(alg) .signing_key_for_algorithm(&alg)
.context("no suitable key found")?; .context("no suitable key found")?;
claims::AT_HASH.insert(&mut claims, hash_token(alg, &access_token_str)?)?; claims::AT_HASH.insert(&mut claims, hash_token(&alg, &access_token_str)?)?;
claims::C_HASH.insert(&mut claims, hash_token(alg, &grant.code)?)?; claims::C_HASH.insert(&mut claims, hash_token(&alg, &grant.code)?)?;
let signer = key.params().signing_key_for_alg(&alg)?;
let header = JsonWebSignatureHeader::new(alg) let header = JsonWebSignatureHeader::new(alg)
.with_kid(key.kid().context("key has no `kid` for some reason")?); .with_kid(key.kid().context("key has no `kid` for some reason")?);
let signer = key.params().signing_key_for_alg(alg)?;
let id_token = Jwt::sign(header, claims, &signer)?; let id_token = Jwt::sign(header, claims, &signer)?;
Some(id_token.as_str().to_owned()) Some(id_token.as_str().to_owned())

View File

@ -75,12 +75,12 @@ pub async fn get(
if let Some(alg) = session.client.userinfo_signed_response_alg { if let Some(alg) = session.client.userinfo_signed_response_alg {
let key = key_store let key = key_store
.signing_key_for_algorithm(alg) .signing_key_for_algorithm(&alg)
.context("no suitable key found")?; .context("no suitable key found")?;
let signer = key.params().signing_key_for_alg(&alg)?;
let header = JsonWebSignatureHeader::new(alg) let header = JsonWebSignatureHeader::new(alg)
.with_kid(key.kid().context("key has no `kid` for some reason")?); .with_kid(key.kid().context("key has no `kid` for some reason")?);
let signer = key.params().signing_key_for_alg(alg)?;
let user_info = SignedUserInfo { let user_info = SignedUserInfo {
iss: url_builder.oidc_issuer().to_string(), iss: url_builder.oidc_issuer().to_string(),

View File

@ -105,7 +105,7 @@ impl Display for File {
use parse_display::{{Display, FromStr}}; use parse_display::{{Display, FromStr}};
use schemars::JsonSchema; use schemars::JsonSchema;
use serde::{{Deserialize, Serialize}};"#, use serde_with::{{DeserializeFromStr, SerializeDisplay}};"#,
self.registry_name, self.registry_url, self.registry_name, self.registry_url,
)?; )?;
@ -116,6 +116,14 @@ use serde::{{Deserialize, Serialize}};"#,
continue; continue;
}; };
let is_exhaustive = section.key == "OAuthAuthorizationEndpointResponseType";
let non_exhaustive_attr = if is_exhaustive {
""
} else {
"\n#[non_exhaustive]"
};
write!( write!(
f, f,
r#" r#"
@ -125,7 +133,6 @@ use serde::{{Deserialize, Serialize}};"#,
#[derive( #[derive(
Debug, Debug,
Clone, Clone,
Copy,
PartialEq, PartialEq,
Eq, Eq,
PartialOrd, PartialOrd,
@ -133,13 +140,14 @@ use serde::{{Deserialize, Serialize}};"#,
Hash, Hash,
Display, Display,
FromStr, FromStr,
Serialize, SerializeDisplay,
Deserialize, DeserializeFromStr,
JsonSchema, JsonSchema,
)] )]{}
pub enum {} {{"#, pub enum {} {{"#,
section.doc, section.doc,
section.url.unwrap(), section.url.unwrap(),
non_exhaustive_attr,
section.key, section.key,
)?; )?;
for member in list { for member in list {
@ -149,10 +157,20 @@ pub enum {} {{"#,
} else { } else {
writeln!(f, " /// `{}`", member.value)?; writeln!(f, " /// `{}`", member.value)?;
} }
writeln!(f, " #[serde(rename = \"{}\")]", member.value)?; writeln!(f, " #[schemars(rename = \"{}\")]", member.value)?;
writeln!(f, " #[display(\"{}\")]", member.value)?; writeln!(f, " #[display(\"{}\")]", member.value)?;
writeln!(f, " {},", member.enum_name)?; writeln!(f, " {},", member.enum_name)?;
} }
if !is_exhaustive {
// Add a variant for custom enums
writeln!(f)?;
writeln!(f, " /// An unknown value.")?;
writeln!(f, " #[display(\"{{0}}\")]")?;
writeln!(f, " #[schemars(skip)]")?;
writeln!(f, " Unknown(String),")?;
}
writeln!(f, "}}")?; writeln!(f, "}}")?;
} }

View File

@ -6,6 +6,6 @@ edition = "2021"
license = "Apache-2.0" license = "Apache-2.0"
[dependencies] [dependencies]
serde = "1.0.145" serde_with = "2.0.0"
schemars = "0.8.10" schemars = "0.8.10"
parse-display = "0.6.0" parse-display = "0.6.0"

View File

@ -19,7 +19,7 @@
use parse_display::{Display, FromStr}; use parse_display::{Display, FromStr};
use schemars::JsonSchema; use schemars::JsonSchema;
use serde::{Deserialize, Serialize}; use serde_with::{DeserializeFromStr, SerializeDisplay};
/// JSON Web Signature "alg" parameter /// JSON Web Signature "alg" parameter
/// ///
@ -27,7 +27,6 @@ use serde::{Deserialize, Serialize};
#[derive( #[derive(
Debug, Debug,
Clone, Clone,
Copy,
PartialEq, PartialEq,
Eq, Eq,
PartialOrd, PartialOrd,
@ -35,85 +34,91 @@ use serde::{Deserialize, Serialize};
Hash, Hash,
Display, Display,
FromStr, FromStr,
Serialize, SerializeDisplay,
Deserialize, DeserializeFromStr,
JsonSchema, JsonSchema,
)] )]
#[non_exhaustive]
pub enum JsonWebSignatureAlg { pub enum JsonWebSignatureAlg {
/// HMAC using SHA-256 /// HMAC using SHA-256
#[serde(rename = "HS256")] #[schemars(rename = "HS256")]
#[display("HS256")] #[display("HS256")]
Hs256, Hs256,
/// HMAC using SHA-384 /// HMAC using SHA-384
#[serde(rename = "HS384")] #[schemars(rename = "HS384")]
#[display("HS384")] #[display("HS384")]
Hs384, Hs384,
/// HMAC using SHA-512 /// HMAC using SHA-512
#[serde(rename = "HS512")] #[schemars(rename = "HS512")]
#[display("HS512")] #[display("HS512")]
Hs512, Hs512,
/// RSASSA-PKCS1-v1_5 using SHA-256 /// RSASSA-PKCS1-v1_5 using SHA-256
#[serde(rename = "RS256")] #[schemars(rename = "RS256")]
#[display("RS256")] #[display("RS256")]
Rs256, Rs256,
/// RSASSA-PKCS1-v1_5 using SHA-384 /// RSASSA-PKCS1-v1_5 using SHA-384
#[serde(rename = "RS384")] #[schemars(rename = "RS384")]
#[display("RS384")] #[display("RS384")]
Rs384, Rs384,
/// RSASSA-PKCS1-v1_5 using SHA-512 /// RSASSA-PKCS1-v1_5 using SHA-512
#[serde(rename = "RS512")] #[schemars(rename = "RS512")]
#[display("RS512")] #[display("RS512")]
Rs512, Rs512,
/// ECDSA using P-256 and SHA-256 /// ECDSA using P-256 and SHA-256
#[serde(rename = "ES256")] #[schemars(rename = "ES256")]
#[display("ES256")] #[display("ES256")]
Es256, Es256,
/// ECDSA using P-384 and SHA-384 /// ECDSA using P-384 and SHA-384
#[serde(rename = "ES384")] #[schemars(rename = "ES384")]
#[display("ES384")] #[display("ES384")]
Es384, Es384,
/// ECDSA using P-521 and SHA-512 /// ECDSA using P-521 and SHA-512
#[serde(rename = "ES512")] #[schemars(rename = "ES512")]
#[display("ES512")] #[display("ES512")]
Es512, Es512,
/// RSASSA-PSS using SHA-256 and MGF1 with SHA-256 /// RSASSA-PSS using SHA-256 and MGF1 with SHA-256
#[serde(rename = "PS256")] #[schemars(rename = "PS256")]
#[display("PS256")] #[display("PS256")]
Ps256, Ps256,
/// RSASSA-PSS using SHA-384 and MGF1 with SHA-384 /// RSASSA-PSS using SHA-384 and MGF1 with SHA-384
#[serde(rename = "PS384")] #[schemars(rename = "PS384")]
#[display("PS384")] #[display("PS384")]
Ps384, Ps384,
/// RSASSA-PSS using SHA-512 and MGF1 with SHA-512 /// RSASSA-PSS using SHA-512 and MGF1 with SHA-512
#[serde(rename = "PS512")] #[schemars(rename = "PS512")]
#[display("PS512")] #[display("PS512")]
Ps512, Ps512,
/// No digital signature or MAC performed /// No digital signature or MAC performed
#[serde(rename = "none")] #[schemars(rename = "none")]
#[display("none")] #[display("none")]
None, None,
/// EdDSA signature algorithms /// EdDSA signature algorithms
#[serde(rename = "EdDSA")] #[schemars(rename = "EdDSA")]
#[display("EdDSA")] #[display("EdDSA")]
EdDsa, EdDsa,
/// ECDSA using secp256k1 curve and SHA-256 /// ECDSA using secp256k1 curve and SHA-256
#[serde(rename = "ES256K")] #[schemars(rename = "ES256K")]
#[display("ES256K")] #[display("ES256K")]
Es256K, Es256K,
/// An unknown value.
#[display("{0}")]
#[schemars(skip)]
Unknown(String),
} }
/// JSON Web Encryption "alg" parameter /// JSON Web Encryption "alg" parameter
@ -122,7 +127,6 @@ pub enum JsonWebSignatureAlg {
#[derive( #[derive(
Debug, Debug,
Clone, Clone,
Copy,
PartialEq, PartialEq,
Eq, Eq,
PartialOrd, PartialOrd,
@ -130,105 +134,111 @@ pub enum JsonWebSignatureAlg {
Hash, Hash,
Display, Display,
FromStr, FromStr,
Serialize, SerializeDisplay,
Deserialize, DeserializeFromStr,
JsonSchema, JsonSchema,
)] )]
#[non_exhaustive]
pub enum JsonWebEncryptionAlg { pub enum JsonWebEncryptionAlg {
/// RSAES-PKCS1-v1_5 /// RSAES-PKCS1-v1_5
#[serde(rename = "RSA1_5")] #[schemars(rename = "RSA1_5")]
#[display("RSA1_5")] #[display("RSA1_5")]
Rsa15, Rsa15,
/// RSAES OAEP using default parameters /// RSAES OAEP using default parameters
#[serde(rename = "RSA-OAEP")] #[schemars(rename = "RSA-OAEP")]
#[display("RSA-OAEP")] #[display("RSA-OAEP")]
RsaOaep, RsaOaep,
/// RSAES OAEP using SHA-256 and MGF1 with SHA-256 /// RSAES OAEP using SHA-256 and MGF1 with SHA-256
#[serde(rename = "RSA-OAEP-256")] #[schemars(rename = "RSA-OAEP-256")]
#[display("RSA-OAEP-256")] #[display("RSA-OAEP-256")]
RsaOaep256, RsaOaep256,
/// AES Key Wrap using 128-bit key /// AES Key Wrap using 128-bit key
#[serde(rename = "A128KW")] #[schemars(rename = "A128KW")]
#[display("A128KW")] #[display("A128KW")]
A128Kw, A128Kw,
/// AES Key Wrap using 192-bit key /// AES Key Wrap using 192-bit key
#[serde(rename = "A192KW")] #[schemars(rename = "A192KW")]
#[display("A192KW")] #[display("A192KW")]
A192Kw, A192Kw,
/// AES Key Wrap using 256-bit key /// AES Key Wrap using 256-bit key
#[serde(rename = "A256KW")] #[schemars(rename = "A256KW")]
#[display("A256KW")] #[display("A256KW")]
A256Kw, A256Kw,
/// Direct use of a shared symmetric key /// Direct use of a shared symmetric key
#[serde(rename = "dir")] #[schemars(rename = "dir")]
#[display("dir")] #[display("dir")]
Dir, Dir,
/// ECDH-ES using Concat KDF /// ECDH-ES using Concat KDF
#[serde(rename = "ECDH-ES")] #[schemars(rename = "ECDH-ES")]
#[display("ECDH-ES")] #[display("ECDH-ES")]
EcdhEs, EcdhEs,
/// ECDH-ES using Concat KDF and "A128KW" wrapping /// ECDH-ES using Concat KDF and "A128KW" wrapping
#[serde(rename = "ECDH-ES+A128KW")] #[schemars(rename = "ECDH-ES+A128KW")]
#[display("ECDH-ES+A128KW")] #[display("ECDH-ES+A128KW")]
EcdhEsA128Kw, EcdhEsA128Kw,
/// ECDH-ES using Concat KDF and "A192KW" wrapping /// ECDH-ES using Concat KDF and "A192KW" wrapping
#[serde(rename = "ECDH-ES+A192KW")] #[schemars(rename = "ECDH-ES+A192KW")]
#[display("ECDH-ES+A192KW")] #[display("ECDH-ES+A192KW")]
EcdhEsA192Kw, EcdhEsA192Kw,
/// ECDH-ES using Concat KDF and "A256KW" wrapping /// ECDH-ES using Concat KDF and "A256KW" wrapping
#[serde(rename = "ECDH-ES+A256KW")] #[schemars(rename = "ECDH-ES+A256KW")]
#[display("ECDH-ES+A256KW")] #[display("ECDH-ES+A256KW")]
EcdhEsA256Kw, EcdhEsA256Kw,
/// Key wrapping with AES GCM using 128-bit key /// Key wrapping with AES GCM using 128-bit key
#[serde(rename = "A128GCMKW")] #[schemars(rename = "A128GCMKW")]
#[display("A128GCMKW")] #[display("A128GCMKW")]
A128Gcmkw, A128Gcmkw,
/// Key wrapping with AES GCM using 192-bit key /// Key wrapping with AES GCM using 192-bit key
#[serde(rename = "A192GCMKW")] #[schemars(rename = "A192GCMKW")]
#[display("A192GCMKW")] #[display("A192GCMKW")]
A192Gcmkw, A192Gcmkw,
/// Key wrapping with AES GCM using 256-bit key /// Key wrapping with AES GCM using 256-bit key
#[serde(rename = "A256GCMKW")] #[schemars(rename = "A256GCMKW")]
#[display("A256GCMKW")] #[display("A256GCMKW")]
A256Gcmkw, A256Gcmkw,
/// PBES2 with HMAC SHA-256 and "A128KW" wrapping /// PBES2 with HMAC SHA-256 and "A128KW" wrapping
#[serde(rename = "PBES2-HS256+A128KW")] #[schemars(rename = "PBES2-HS256+A128KW")]
#[display("PBES2-HS256+A128KW")] #[display("PBES2-HS256+A128KW")]
Pbes2Hs256A128Kw, Pbes2Hs256A128Kw,
/// PBES2 with HMAC SHA-384 and "A192KW" wrapping /// PBES2 with HMAC SHA-384 and "A192KW" wrapping
#[serde(rename = "PBES2-HS384+A192KW")] #[schemars(rename = "PBES2-HS384+A192KW")]
#[display("PBES2-HS384+A192KW")] #[display("PBES2-HS384+A192KW")]
Pbes2Hs384A192Kw, Pbes2Hs384A192Kw,
/// PBES2 with HMAC SHA-512 and "A256KW" wrapping /// PBES2 with HMAC SHA-512 and "A256KW" wrapping
#[serde(rename = "PBES2-HS512+A256KW")] #[schemars(rename = "PBES2-HS512+A256KW")]
#[display("PBES2-HS512+A256KW")] #[display("PBES2-HS512+A256KW")]
Pbes2Hs512A256Kw, Pbes2Hs512A256Kw,
/// RSA-OAEP using SHA-384 and MGF1 with SHA-384 /// RSA-OAEP using SHA-384 and MGF1 with SHA-384
#[serde(rename = "RSA-OAEP-384")] #[schemars(rename = "RSA-OAEP-384")]
#[display("RSA-OAEP-384")] #[display("RSA-OAEP-384")]
RsaOaep384, RsaOaep384,
/// RSA-OAEP using SHA-512 and MGF1 with SHA-512 /// RSA-OAEP using SHA-512 and MGF1 with SHA-512
#[serde(rename = "RSA-OAEP-512")] #[schemars(rename = "RSA-OAEP-512")]
#[display("RSA-OAEP-512")] #[display("RSA-OAEP-512")]
RsaOaep512, RsaOaep512,
/// An unknown value.
#[display("{0}")]
#[schemars(skip)]
Unknown(String),
} }
/// JSON Web Encryption "enc" parameter /// JSON Web Encryption "enc" parameter
@ -237,7 +247,6 @@ pub enum JsonWebEncryptionAlg {
#[derive( #[derive(
Debug, Debug,
Clone, Clone,
Copy,
PartialEq, PartialEq,
Eq, Eq,
PartialOrd, PartialOrd,
@ -245,40 +254,46 @@ pub enum JsonWebEncryptionAlg {
Hash, Hash,
Display, Display,
FromStr, FromStr,
Serialize, SerializeDisplay,
Deserialize, DeserializeFromStr,
JsonSchema, JsonSchema,
)] )]
#[non_exhaustive]
pub enum JsonWebEncryptionEnc { pub enum JsonWebEncryptionEnc {
/// AES_128_CBC_HMAC_SHA_256 authenticated encryption algorithm /// AES_128_CBC_HMAC_SHA_256 authenticated encryption algorithm
#[serde(rename = "A128CBC-HS256")] #[schemars(rename = "A128CBC-HS256")]
#[display("A128CBC-HS256")] #[display("A128CBC-HS256")]
A128CbcHs256, A128CbcHs256,
/// AES_192_CBC_HMAC_SHA_384 authenticated encryption algorithm /// AES_192_CBC_HMAC_SHA_384 authenticated encryption algorithm
#[serde(rename = "A192CBC-HS384")] #[schemars(rename = "A192CBC-HS384")]
#[display("A192CBC-HS384")] #[display("A192CBC-HS384")]
A192CbcHs384, A192CbcHs384,
/// AES_256_CBC_HMAC_SHA_512 authenticated encryption algorithm /// AES_256_CBC_HMAC_SHA_512 authenticated encryption algorithm
#[serde(rename = "A256CBC-HS512")] #[schemars(rename = "A256CBC-HS512")]
#[display("A256CBC-HS512")] #[display("A256CBC-HS512")]
A256CbcHs512, A256CbcHs512,
/// AES GCM using 128-bit key /// AES GCM using 128-bit key
#[serde(rename = "A128GCM")] #[schemars(rename = "A128GCM")]
#[display("A128GCM")] #[display("A128GCM")]
A128Gcm, A128Gcm,
/// AES GCM using 192-bit key /// AES GCM using 192-bit key
#[serde(rename = "A192GCM")] #[schemars(rename = "A192GCM")]
#[display("A192GCM")] #[display("A192GCM")]
A192Gcm, A192Gcm,
/// AES GCM using 256-bit key /// AES GCM using 256-bit key
#[serde(rename = "A256GCM")] #[schemars(rename = "A256GCM")]
#[display("A256GCM")] #[display("A256GCM")]
A256Gcm, A256Gcm,
/// An unknown value.
#[display("{0}")]
#[schemars(skip)]
Unknown(String),
} }
/// JSON Web Encryption Compression Algorithm /// JSON Web Encryption Compression Algorithm
@ -287,7 +302,6 @@ pub enum JsonWebEncryptionEnc {
#[derive( #[derive(
Debug, Debug,
Clone, Clone,
Copy,
PartialEq, PartialEq,
Eq, Eq,
PartialOrd, PartialOrd,
@ -295,15 +309,21 @@ pub enum JsonWebEncryptionEnc {
Hash, Hash,
Display, Display,
FromStr, FromStr,
Serialize, SerializeDisplay,
Deserialize, DeserializeFromStr,
JsonSchema, JsonSchema,
)] )]
#[non_exhaustive]
pub enum JsonWebEncryptionCompressionAlgorithm { pub enum JsonWebEncryptionCompressionAlgorithm {
/// DEFLATE /// DEFLATE
#[serde(rename = "DEF")] #[schemars(rename = "DEF")]
#[display("DEF")] #[display("DEF")]
Def, Def,
/// An unknown value.
#[display("{0}")]
#[schemars(skip)]
Unknown(String),
} }
/// JSON Web Key Type /// JSON Web Key Type
@ -312,7 +332,6 @@ pub enum JsonWebEncryptionCompressionAlgorithm {
#[derive( #[derive(
Debug, Debug,
Clone, Clone,
Copy,
PartialEq, PartialEq,
Eq, Eq,
PartialOrd, PartialOrd,
@ -320,30 +339,36 @@ pub enum JsonWebEncryptionCompressionAlgorithm {
Hash, Hash,
Display, Display,
FromStr, FromStr,
Serialize, SerializeDisplay,
Deserialize, DeserializeFromStr,
JsonSchema, JsonSchema,
)] )]
#[non_exhaustive]
pub enum JsonWebKeyType { pub enum JsonWebKeyType {
/// Elliptic Curve /// Elliptic Curve
#[serde(rename = "EC")] #[schemars(rename = "EC")]
#[display("EC")] #[display("EC")]
Ec, Ec,
/// RSA /// RSA
#[serde(rename = "RSA")] #[schemars(rename = "RSA")]
#[display("RSA")] #[display("RSA")]
Rsa, Rsa,
/// Octet sequence /// Octet sequence
#[serde(rename = "oct")] #[schemars(rename = "oct")]
#[display("oct")] #[display("oct")]
Oct, Oct,
/// Octet string key pairs /// Octet string key pairs
#[serde(rename = "OKP")] #[schemars(rename = "OKP")]
#[display("OKP")] #[display("OKP")]
Okp, Okp,
/// An unknown value.
#[display("{0}")]
#[schemars(skip)]
Unknown(String),
} }
/// JSON Web Key EC Elliptic Curve /// JSON Web Key EC Elliptic Curve
@ -352,7 +377,6 @@ pub enum JsonWebKeyType {
#[derive( #[derive(
Debug, Debug,
Clone, Clone,
Copy,
PartialEq, PartialEq,
Eq, Eq,
PartialOrd, PartialOrd,
@ -360,30 +384,36 @@ pub enum JsonWebKeyType {
Hash, Hash,
Display, Display,
FromStr, FromStr,
Serialize, SerializeDisplay,
Deserialize, DeserializeFromStr,
JsonSchema, JsonSchema,
)] )]
#[non_exhaustive]
pub enum JsonWebKeyEcEllipticCurve { pub enum JsonWebKeyEcEllipticCurve {
/// P-256 Curve /// P-256 Curve
#[serde(rename = "P-256")] #[schemars(rename = "P-256")]
#[display("P-256")] #[display("P-256")]
P256, P256,
/// P-384 Curve /// P-384 Curve
#[serde(rename = "P-384")] #[schemars(rename = "P-384")]
#[display("P-384")] #[display("P-384")]
P384, P384,
/// P-521 Curve /// P-521 Curve
#[serde(rename = "P-521")] #[schemars(rename = "P-521")]
#[display("P-521")] #[display("P-521")]
P521, P521,
/// SECG secp256k1 curve /// SECG secp256k1 curve
#[serde(rename = "secp256k1")] #[schemars(rename = "secp256k1")]
#[display("secp256k1")] #[display("secp256k1")]
Secp256K1, Secp256K1,
/// An unknown value.
#[display("{0}")]
#[schemars(skip)]
Unknown(String),
} }
/// JSON Web Key OKP Elliptic Curve /// JSON Web Key OKP Elliptic Curve
@ -392,7 +422,6 @@ pub enum JsonWebKeyEcEllipticCurve {
#[derive( #[derive(
Debug, Debug,
Clone, Clone,
Copy,
PartialEq, PartialEq,
Eq, Eq,
PartialOrd, PartialOrd,
@ -400,30 +429,36 @@ pub enum JsonWebKeyEcEllipticCurve {
Hash, Hash,
Display, Display,
FromStr, FromStr,
Serialize, SerializeDisplay,
Deserialize, DeserializeFromStr,
JsonSchema, JsonSchema,
)] )]
#[non_exhaustive]
pub enum JsonWebKeyOkpEllipticCurve { pub enum JsonWebKeyOkpEllipticCurve {
/// Ed25519 signature algorithm key pairs /// Ed25519 signature algorithm key pairs
#[serde(rename = "Ed25519")] #[schemars(rename = "Ed25519")]
#[display("Ed25519")] #[display("Ed25519")]
Ed25519, Ed25519,
/// Ed448 signature algorithm key pairs /// Ed448 signature algorithm key pairs
#[serde(rename = "Ed448")] #[schemars(rename = "Ed448")]
#[display("Ed448")] #[display("Ed448")]
Ed448, Ed448,
/// X25519 function key pairs /// X25519 function key pairs
#[serde(rename = "X25519")] #[schemars(rename = "X25519")]
#[display("X25519")] #[display("X25519")]
X25519, X25519,
/// X448 function key pairs /// X448 function key pairs
#[serde(rename = "X448")] #[schemars(rename = "X448")]
#[display("X448")] #[display("X448")]
X448, X448,
/// An unknown value.
#[display("{0}")]
#[schemars(skip)]
Unknown(String),
} }
/// JSON Web Key Use /// JSON Web Key Use
@ -432,7 +467,6 @@ pub enum JsonWebKeyOkpEllipticCurve {
#[derive( #[derive(
Debug, Debug,
Clone, Clone,
Copy,
PartialEq, PartialEq,
Eq, Eq,
PartialOrd, PartialOrd,
@ -440,20 +474,26 @@ pub enum JsonWebKeyOkpEllipticCurve {
Hash, Hash,
Display, Display,
FromStr, FromStr,
Serialize, SerializeDisplay,
Deserialize, DeserializeFromStr,
JsonSchema, JsonSchema,
)] )]
#[non_exhaustive]
pub enum JsonWebKeyUse { pub enum JsonWebKeyUse {
/// Digital Signature or MAC /// Digital Signature or MAC
#[serde(rename = "sig")] #[schemars(rename = "sig")]
#[display("sig")] #[display("sig")]
Sig, Sig,
/// Encryption /// Encryption
#[serde(rename = "enc")] #[schemars(rename = "enc")]
#[display("enc")] #[display("enc")]
Enc, Enc,
/// An unknown value.
#[display("{0}")]
#[schemars(skip)]
Unknown(String),
} }
/// JSON Web Key Operation /// JSON Web Key Operation
@ -462,7 +502,6 @@ pub enum JsonWebKeyUse {
#[derive( #[derive(
Debug, Debug,
Clone, Clone,
Copy,
PartialEq, PartialEq,
Eq, Eq,
PartialOrd, PartialOrd,
@ -470,48 +509,54 @@ pub enum JsonWebKeyUse {
Hash, Hash,
Display, Display,
FromStr, FromStr,
Serialize, SerializeDisplay,
Deserialize, DeserializeFromStr,
JsonSchema, JsonSchema,
)] )]
#[non_exhaustive]
pub enum JsonWebKeyOperation { pub enum JsonWebKeyOperation {
/// Compute digital signature or MAC /// Compute digital signature or MAC
#[serde(rename = "sign")] #[schemars(rename = "sign")]
#[display("sign")] #[display("sign")]
Sign, Sign,
/// Verify digital signature or MAC /// Verify digital signature or MAC
#[serde(rename = "verify")] #[schemars(rename = "verify")]
#[display("verify")] #[display("verify")]
Verify, Verify,
/// Encrypt content /// Encrypt content
#[serde(rename = "encrypt")] #[schemars(rename = "encrypt")]
#[display("encrypt")] #[display("encrypt")]
Encrypt, Encrypt,
/// Decrypt content and validate decryption, if applicable /// Decrypt content and validate decryption, if applicable
#[serde(rename = "decrypt")] #[schemars(rename = "decrypt")]
#[display("decrypt")] #[display("decrypt")]
Decrypt, Decrypt,
/// Encrypt key /// Encrypt key
#[serde(rename = "wrapKey")] #[schemars(rename = "wrapKey")]
#[display("wrapKey")] #[display("wrapKey")]
WrapKey, WrapKey,
/// Decrypt key and validate decryption, if applicable /// Decrypt key and validate decryption, if applicable
#[serde(rename = "unwrapKey")] #[schemars(rename = "unwrapKey")]
#[display("unwrapKey")] #[display("unwrapKey")]
UnwrapKey, UnwrapKey,
/// Derive key /// Derive key
#[serde(rename = "deriveKey")] #[schemars(rename = "deriveKey")]
#[display("deriveKey")] #[display("deriveKey")]
DeriveKey, DeriveKey,
/// Derive bits not to be used as a key /// Derive bits not to be used as a key
#[serde(rename = "deriveBits")] #[schemars(rename = "deriveBits")]
#[display("deriveBits")] #[display("deriveBits")]
DeriveBits, DeriveBits,
/// An unknown value.
#[display("{0}")]
#[schemars(skip)]
Unknown(String),
} }

View File

@ -19,7 +19,7 @@
use parse_display::{Display, FromStr}; use parse_display::{Display, FromStr};
use schemars::JsonSchema; use schemars::JsonSchema;
use serde::{Deserialize, Serialize}; use serde_with::{DeserializeFromStr, SerializeDisplay};
/// OAuth Access Token Type /// OAuth Access Token Type
/// ///
@ -27,7 +27,6 @@ use serde::{Deserialize, Serialize};
#[derive( #[derive(
Debug, Debug,
Clone, Clone,
Copy,
PartialEq, PartialEq,
Eq, Eq,
PartialOrd, PartialOrd,
@ -35,25 +34,31 @@ use serde::{Deserialize, Serialize};
Hash, Hash,
Display, Display,
FromStr, FromStr,
Serialize, SerializeDisplay,
Deserialize, DeserializeFromStr,
JsonSchema, JsonSchema,
)] )]
#[non_exhaustive]
pub enum OAuthAccessTokenType { pub enum OAuthAccessTokenType {
/// `Bearer` /// `Bearer`
#[serde(rename = "Bearer")] #[schemars(rename = "Bearer")]
#[display("Bearer")] #[display("Bearer")]
Bearer, Bearer,
/// `N_A` /// `N_A`
#[serde(rename = "N_A")] #[schemars(rename = "N_A")]
#[display("N_A")] #[display("N_A")]
Na, Na,
/// `PoP` /// `PoP`
#[serde(rename = "PoP")] #[schemars(rename = "PoP")]
#[display("PoP")] #[display("PoP")]
PoP, PoP,
/// An unknown value.
#[display("{0}")]
#[schemars(skip)]
Unknown(String),
} }
/// OAuth Authorization Endpoint Response Type /// OAuth Authorization Endpoint Response Type
@ -62,7 +67,6 @@ pub enum OAuthAccessTokenType {
#[derive( #[derive(
Debug, Debug,
Clone, Clone,
Copy,
PartialEq, PartialEq,
Eq, Eq,
PartialOrd, PartialOrd,
@ -70,48 +74,48 @@ pub enum OAuthAccessTokenType {
Hash, Hash,
Display, Display,
FromStr, FromStr,
Serialize, SerializeDisplay,
Deserialize, DeserializeFromStr,
JsonSchema, JsonSchema,
)] )]
pub enum OAuthAuthorizationEndpointResponseType { pub enum OAuthAuthorizationEndpointResponseType {
/// `code` /// `code`
#[serde(rename = "code")] #[schemars(rename = "code")]
#[display("code")] #[display("code")]
Code, Code,
/// `code id_token` /// `code id_token`
#[serde(rename = "code id_token")] #[schemars(rename = "code id_token")]
#[display("code id_token")] #[display("code id_token")]
CodeIdToken, CodeIdToken,
/// `code id_token token` /// `code id_token token`
#[serde(rename = "code id_token token")] #[schemars(rename = "code id_token token")]
#[display("code id_token token")] #[display("code id_token token")]
CodeIdTokenToken, CodeIdTokenToken,
/// `code token` /// `code token`
#[serde(rename = "code token")] #[schemars(rename = "code token")]
#[display("code token")] #[display("code token")]
CodeToken, CodeToken,
/// `id_token` /// `id_token`
#[serde(rename = "id_token")] #[schemars(rename = "id_token")]
#[display("id_token")] #[display("id_token")]
IdToken, IdToken,
/// `id_token token` /// `id_token token`
#[serde(rename = "id_token token")] #[schemars(rename = "id_token token")]
#[display("id_token token")] #[display("id_token token")]
IdTokenToken, IdTokenToken,
/// `none` /// `none`
#[serde(rename = "none")] #[schemars(rename = "none")]
#[display("none")] #[display("none")]
None, None,
/// `token` /// `token`
#[serde(rename = "token")] #[schemars(rename = "token")]
#[display("token")] #[display("token")]
Token, Token,
} }
@ -122,7 +126,6 @@ pub enum OAuthAuthorizationEndpointResponseType {
#[derive( #[derive(
Debug, Debug,
Clone, Clone,
Copy,
PartialEq, PartialEq,
Eq, Eq,
PartialOrd, PartialOrd,
@ -130,25 +133,31 @@ pub enum OAuthAuthorizationEndpointResponseType {
Hash, Hash,
Display, Display,
FromStr, FromStr,
Serialize, SerializeDisplay,
Deserialize, DeserializeFromStr,
JsonSchema, JsonSchema,
)] )]
#[non_exhaustive]
pub enum OAuthTokenTypeHint { pub enum OAuthTokenTypeHint {
/// `access_token` /// `access_token`
#[serde(rename = "access_token")] #[schemars(rename = "access_token")]
#[display("access_token")] #[display("access_token")]
AccessToken, AccessToken,
/// `refresh_token` /// `refresh_token`
#[serde(rename = "refresh_token")] #[schemars(rename = "refresh_token")]
#[display("refresh_token")] #[display("refresh_token")]
RefreshToken, RefreshToken,
/// `pct` /// `pct`
#[serde(rename = "pct")] #[schemars(rename = "pct")]
#[display("pct")] #[display("pct")]
Pct, Pct,
/// An unknown value.
#[display("{0}")]
#[schemars(skip)]
Unknown(String),
} }
/// OAuth Token Endpoint Authentication Method /// OAuth Token Endpoint Authentication Method
@ -157,7 +166,6 @@ pub enum OAuthTokenTypeHint {
#[derive( #[derive(
Debug, Debug,
Clone, Clone,
Copy,
PartialEq, PartialEq,
Eq, Eq,
PartialOrd, PartialOrd,
@ -165,45 +173,51 @@ pub enum OAuthTokenTypeHint {
Hash, Hash,
Display, Display,
FromStr, FromStr,
Serialize, SerializeDisplay,
Deserialize, DeserializeFromStr,
JsonSchema, JsonSchema,
)] )]
#[non_exhaustive]
pub enum OAuthClientAuthenticationMethod { pub enum OAuthClientAuthenticationMethod {
/// `none` /// `none`
#[serde(rename = "none")] #[schemars(rename = "none")]
#[display("none")] #[display("none")]
None, None,
/// `client_secret_post` /// `client_secret_post`
#[serde(rename = "client_secret_post")] #[schemars(rename = "client_secret_post")]
#[display("client_secret_post")] #[display("client_secret_post")]
ClientSecretPost, ClientSecretPost,
/// `client_secret_basic` /// `client_secret_basic`
#[serde(rename = "client_secret_basic")] #[schemars(rename = "client_secret_basic")]
#[display("client_secret_basic")] #[display("client_secret_basic")]
ClientSecretBasic, ClientSecretBasic,
/// `client_secret_jwt` /// `client_secret_jwt`
#[serde(rename = "client_secret_jwt")] #[schemars(rename = "client_secret_jwt")]
#[display("client_secret_jwt")] #[display("client_secret_jwt")]
ClientSecretJwt, ClientSecretJwt,
/// `private_key_jwt` /// `private_key_jwt`
#[serde(rename = "private_key_jwt")] #[schemars(rename = "private_key_jwt")]
#[display("private_key_jwt")] #[display("private_key_jwt")]
PrivateKeyJwt, PrivateKeyJwt,
/// `tls_client_auth` /// `tls_client_auth`
#[serde(rename = "tls_client_auth")] #[schemars(rename = "tls_client_auth")]
#[display("tls_client_auth")] #[display("tls_client_auth")]
TlsClientAuth, TlsClientAuth,
/// `self_signed_tls_client_auth` /// `self_signed_tls_client_auth`
#[serde(rename = "self_signed_tls_client_auth")] #[schemars(rename = "self_signed_tls_client_auth")]
#[display("self_signed_tls_client_auth")] #[display("self_signed_tls_client_auth")]
SelfSignedTlsClientAuth, SelfSignedTlsClientAuth,
/// An unknown value.
#[display("{0}")]
#[schemars(skip)]
Unknown(String),
} }
/// PKCE Code Challenge Method /// PKCE Code Challenge Method
@ -212,7 +226,6 @@ pub enum OAuthClientAuthenticationMethod {
#[derive( #[derive(
Debug, Debug,
Clone, Clone,
Copy,
PartialEq, PartialEq,
Eq, Eq,
PartialOrd, PartialOrd,
@ -220,18 +233,24 @@ pub enum OAuthClientAuthenticationMethod {
Hash, Hash,
Display, Display,
FromStr, FromStr,
Serialize, SerializeDisplay,
Deserialize, DeserializeFromStr,
JsonSchema, JsonSchema,
)] )]
#[non_exhaustive]
pub enum PkceCodeChallengeMethod { pub enum PkceCodeChallengeMethod {
/// `plain` /// `plain`
#[serde(rename = "plain")] #[schemars(rename = "plain")]
#[display("plain")] #[display("plain")]
Plain, Plain,
/// `S256` /// `S256`
#[serde(rename = "S256")] #[schemars(rename = "S256")]
#[display("S256")] #[display("S256")]
S256, S256,
/// An unknown value.
#[display("{0}")]
#[schemars(skip)]
Unknown(String),
} }

View File

@ -248,7 +248,7 @@ impl From<&TimeOptions> for TimeNotBefore {
/// Returns an error if the algorithm is not supported. /// Returns an error if the algorithm is not supported.
/// ///
/// [OpenID Connect Core 1.0 specification]: https://openid.net/specs/openid-connect-core-1_0.html#CodeIDToken /// [OpenID Connect Core 1.0 specification]: https://openid.net/specs/openid-connect-core-1_0.html#CodeIDToken
pub fn hash_token(alg: JsonWebSignatureAlg, token: &str) -> anyhow::Result<String> { pub fn hash_token(alg: &JsonWebSignatureAlg, token: &str) -> anyhow::Result<String> {
let bits = match alg { let bits = match alg {
JsonWebSignatureAlg::Hs256 JsonWebSignatureAlg::Hs256
| JsonWebSignatureAlg::Rs256 | JsonWebSignatureAlg::Rs256
@ -281,9 +281,7 @@ pub fn hash_token(alg: JsonWebSignatureAlg, token: &str) -> anyhow::Result<Strin
// Left-most half // Left-most half
hash.get(..32).map(ToOwned::to_owned) hash.get(..32).map(ToOwned::to_owned)
} }
JsonWebSignatureAlg::EdDsa | JsonWebSignatureAlg::None => { _ => return Err(anyhow::anyhow!("unsupported algorithm for hashing")),
return Err(anyhow::anyhow!("unsupported algorithm for hashing"))
}
} }
.context("failed to get first half of hash")?; .context("failed to get first half of hash")?;
@ -292,14 +290,14 @@ pub fn hash_token(alg: JsonWebSignatureAlg, token: &str) -> anyhow::Result<Strin
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct TokenHash<'a> { pub struct TokenHash<'a> {
alg: JsonWebSignatureAlg, alg: &'a JsonWebSignatureAlg,
token: &'a str, token: &'a str,
} }
impl<'a> TokenHash<'a> { impl<'a> TokenHash<'a> {
/// Creates a new `TokenHash` validator for the given algorithm and token. /// Creates a new `TokenHash` validator for the given algorithm and token.
#[must_use] #[must_use]
pub fn new(alg: JsonWebSignatureAlg, token: &'a str) -> Self { pub fn new(alg: &'a JsonWebSignatureAlg, token: &'a str) -> Self {
Self { alg, token } Self { alg, token }
} }
} }

View File

@ -21,7 +21,7 @@ use crate::jwt::JsonWebSignatureHeader;
#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum Constraint<'a> { pub enum Constraint<'a> {
Alg { Alg {
constraint_alg: JsonWebSignatureAlg, constraint_alg: &'a JsonWebSignatureAlg,
}, },
Algs { Algs {
@ -33,17 +33,17 @@ pub enum Constraint<'a> {
}, },
Use { Use {
constraint_use: JsonWebKeyUse, constraint_use: &'a JsonWebKeyUse,
}, },
Kty { Kty {
constraint_kty: JsonWebKeyType, constraint_kty: &'a JsonWebKeyType,
}, },
} }
impl<'a> Constraint<'a> { impl<'a> Constraint<'a> {
#[must_use] #[must_use]
pub fn alg(constraint_alg: JsonWebSignatureAlg) -> Self { pub fn alg(constraint_alg: &'a JsonWebSignatureAlg) -> Self {
Constraint::Alg { constraint_alg } Constraint::Alg { constraint_alg }
} }
@ -58,12 +58,12 @@ impl<'a> Constraint<'a> {
} }
#[must_use] #[must_use]
pub fn use_(constraint_use: JsonWebKeyUse) -> Self { pub fn use_(constraint_use: &'a JsonWebKeyUse) -> Self {
Constraint::Use { constraint_use } Constraint::Use { constraint_use }
} }
#[must_use] #[must_use]
pub fn kty(constraint_kty: JsonWebKeyType) -> Self { pub fn kty(constraint_kty: &'a JsonWebKeyType) -> Self {
Constraint::Kty { constraint_kty } Constraint::Kty { constraint_kty }
} }
} }
@ -76,7 +76,7 @@ pub enum ConstraintDecision {
} }
pub trait Constrainable { pub trait Constrainable {
fn alg(&self) -> Option<JsonWebSignatureAlg> { fn alg(&self) -> Option<&JsonWebSignatureAlg> {
None None
} }
@ -91,7 +91,7 @@ pub trait Constrainable {
} }
/// Usage specified for this key /// Usage specified for this key
fn use_(&self) -> Option<JsonWebKeyUse> { fn use_(&self) -> Option<&JsonWebKeyUse> {
None None
} }
@ -120,7 +120,7 @@ impl<'a> Constraint<'a> {
} }
Constraint::Algs { constraint_algs } => { Constraint::Algs { constraint_algs } => {
if let Some(alg) = constrainable.alg() { if let Some(alg) = constrainable.alg() {
if constraint_algs.contains(&alg) { if constraint_algs.contains(alg) {
ConstraintDecision::Positive ConstraintDecision::Positive
} else { } else {
ConstraintDecision::Negative ConstraintDecision::Negative
@ -158,7 +158,7 @@ impl<'a> Constraint<'a> {
} }
} }
Constraint::Kty { constraint_kty } => { Constraint::Kty { constraint_kty } => {
if *constraint_kty == constrainable.kty() { if **constraint_kty == constrainable.kty() {
ConstraintDecision::Positive ConstraintDecision::Positive
} else { } else {
ConstraintDecision::Negative ConstraintDecision::Negative
@ -217,7 +217,7 @@ impl<'a> ConstraintSet<'a> {
} }
#[must_use] #[must_use]
pub fn alg(mut self, constraint_alg: JsonWebSignatureAlg) -> Self { pub fn alg(mut self, constraint_alg: &'a JsonWebSignatureAlg) -> Self {
self.constraints.insert(Constraint::alg(constraint_alg)); self.constraints.insert(Constraint::alg(constraint_alg));
self self
} }
@ -235,13 +235,13 @@ impl<'a> ConstraintSet<'a> {
} }
#[must_use] #[must_use]
pub fn use_(mut self, constraint_use: JsonWebKeyUse) -> Self { pub fn use_(mut self, constraint_use: &'a JsonWebKeyUse) -> Self {
self.constraints.insert(Constraint::use_(constraint_use)); self.constraints.insert(Constraint::use_(constraint_use));
self self
} }
#[must_use] #[must_use]
pub fn kty(mut self, constraint_kty: JsonWebKeyType) -> Self { pub fn kty(mut self, constraint_kty: &'a JsonWebKeyType) -> Self {
self.constraints.insert(Constraint::kty(constraint_kty)); self.constraints.insert(Constraint::kty(constraint_kty));
self self
} }

View File

@ -59,7 +59,7 @@ impl AsymmetricSigningKey {
#[allow(dead_code)] #[allow(dead_code)]
pub fn from_jwk_and_alg( pub fn from_jwk_and_alg(
params: &JsonWebKeyPrivateParameters, params: &JsonWebKeyPrivateParameters,
alg: JsonWebSignatureAlg, alg: &JsonWebSignatureAlg,
) -> Result<Self, AsymmetricKeyFromJwkError> { ) -> Result<Self, AsymmetricKeyFromJwkError> {
match (params, alg) { match (params, alg) {
(JsonWebKeyPrivateParameters::Rsa(params), alg) => match alg { (JsonWebKeyPrivateParameters::Rsa(params), alg) => match alg {
@ -69,7 +69,7 @@ impl AsymmetricSigningKey {
JsonWebSignatureAlg::Ps256 => Ok(Self::Ps256(params.try_into()?)), JsonWebSignatureAlg::Ps256 => Ok(Self::Ps256(params.try_into()?)),
JsonWebSignatureAlg::Ps384 => Ok(Self::Ps384(params.try_into()?)), JsonWebSignatureAlg::Ps384 => Ok(Self::Ps384(params.try_into()?)),
JsonWebSignatureAlg::Ps512 => Ok(Self::Ps512(params.try_into()?)), JsonWebSignatureAlg::Ps512 => Ok(Self::Ps512(params.try_into()?)),
_ => Err(AsymmetricKeyFromJwkError::KeyNotSuitable { alg }), _ => Err(AsymmetricKeyFromJwkError::KeyNotSuitable { alg: alg.clone() }),
}, },
(JsonWebKeyPrivateParameters::Ec(params), JsonWebSignatureAlg::Es256) (JsonWebKeyPrivateParameters::Ec(params), JsonWebSignatureAlg::Es256)
@ -87,7 +87,7 @@ impl AsymmetricSigningKey {
(JsonWebKeyPrivateParameters::Ec(params), JsonWebSignatureAlg::Es512) (JsonWebKeyPrivateParameters::Ec(params), JsonWebSignatureAlg::Es512)
if params.crv == JsonWebKeyEcEllipticCurve::P521 => if params.crv == JsonWebKeyEcEllipticCurve::P521 =>
{ {
Err(AsymmetricKeyFromJwkError::UnsupportedAlgorithm { alg }) Err(AsymmetricKeyFromJwkError::UnsupportedAlgorithm { alg: alg.clone() })
} }
(JsonWebKeyPrivateParameters::Ec(params), JsonWebSignatureAlg::Es256K) (JsonWebKeyPrivateParameters::Ec(params), JsonWebSignatureAlg::Es256K)
@ -97,10 +97,10 @@ impl AsymmetricSigningKey {
} }
(JsonWebKeyPrivateParameters::Okp(_params), JsonWebSignatureAlg::EdDsa) => { (JsonWebKeyPrivateParameters::Okp(_params), JsonWebSignatureAlg::EdDsa) => {
Err(AsymmetricKeyFromJwkError::UnsupportedAlgorithm { alg }) Err(AsymmetricKeyFromJwkError::UnsupportedAlgorithm { alg: alg.clone() })
} }
_ => Err(AsymmetricKeyFromJwkError::KeyNotSuitable { alg }), _ => Err(AsymmetricKeyFromJwkError::KeyNotSuitable { alg: alg.clone() }),
} }
} }
} }
@ -219,7 +219,7 @@ pub enum AsymmetricVerifyingKey {
impl AsymmetricVerifyingKey { impl AsymmetricVerifyingKey {
pub fn from_jwk_and_alg( pub fn from_jwk_and_alg(
params: &JsonWebKeyPublicParameters, params: &JsonWebKeyPublicParameters,
alg: JsonWebSignatureAlg, alg: &JsonWebSignatureAlg,
) -> Result<Self, AsymmetricKeyFromJwkError> { ) -> Result<Self, AsymmetricKeyFromJwkError> {
match (params, alg) { match (params, alg) {
(JsonWebKeyPublicParameters::Rsa(params), alg) => match alg { (JsonWebKeyPublicParameters::Rsa(params), alg) => match alg {
@ -229,7 +229,7 @@ impl AsymmetricVerifyingKey {
JsonWebSignatureAlg::Ps256 => Ok(Self::Ps256(params.try_into()?)), JsonWebSignatureAlg::Ps256 => Ok(Self::Ps256(params.try_into()?)),
JsonWebSignatureAlg::Ps384 => Ok(Self::Ps384(params.try_into()?)), JsonWebSignatureAlg::Ps384 => Ok(Self::Ps384(params.try_into()?)),
JsonWebSignatureAlg::Ps512 => Ok(Self::Ps512(params.try_into()?)), JsonWebSignatureAlg::Ps512 => Ok(Self::Ps512(params.try_into()?)),
_ => Err(AsymmetricKeyFromJwkError::KeyNotSuitable { alg }), _ => Err(AsymmetricKeyFromJwkError::KeyNotSuitable { alg: alg.clone() }),
}, },
(JsonWebKeyPublicParameters::Ec(params), JsonWebSignatureAlg::Es256) (JsonWebKeyPublicParameters::Ec(params), JsonWebSignatureAlg::Es256)
@ -247,7 +247,7 @@ impl AsymmetricVerifyingKey {
(JsonWebKeyPublicParameters::Ec(params), JsonWebSignatureAlg::Es512) (JsonWebKeyPublicParameters::Ec(params), JsonWebSignatureAlg::Es512)
if params.crv == JsonWebKeyEcEllipticCurve::P521 => if params.crv == JsonWebKeyEcEllipticCurve::P521 =>
{ {
Err(AsymmetricKeyFromJwkError::UnsupportedAlgorithm { alg }) Err(AsymmetricKeyFromJwkError::UnsupportedAlgorithm { alg: alg.clone() })
} }
(JsonWebKeyPublicParameters::Ec(params), JsonWebSignatureAlg::Es256K) (JsonWebKeyPublicParameters::Ec(params), JsonWebSignatureAlg::Es256K)
@ -257,10 +257,10 @@ impl AsymmetricVerifyingKey {
} }
(JsonWebKeyPublicParameters::Okp(_params), JsonWebSignatureAlg::EdDsa) => { (JsonWebKeyPublicParameters::Okp(_params), JsonWebSignatureAlg::EdDsa) => {
Err(AsymmetricKeyFromJwkError::UnsupportedAlgorithm { alg }) Err(AsymmetricKeyFromJwkError::UnsupportedAlgorithm { alg: alg.clone() })
} }
_ => Err(AsymmetricKeyFromJwkError::KeyNotSuitable { alg }), _ => Err(AsymmetricKeyFromJwkError::KeyNotSuitable { alg: alg.clone() }),
} }
} }
} }

View File

@ -33,15 +33,15 @@ pub struct InvalidAlgorithm {
} }
impl SymmetricKey { impl SymmetricKey {
pub const fn new_for_alg( pub fn new_for_alg(key: Vec<u8>, alg: &JsonWebSignatureAlg) -> Result<Self, InvalidAlgorithm> {
key: Vec<u8>,
alg: JsonWebSignatureAlg,
) -> Result<Self, InvalidAlgorithm> {
match alg { match alg {
JsonWebSignatureAlg::Hs256 => Ok(Self::hs256(key)), JsonWebSignatureAlg::Hs256 => Ok(Self::hs256(key)),
JsonWebSignatureAlg::Hs384 => Ok(Self::hs384(key)), JsonWebSignatureAlg::Hs384 => Ok(Self::hs384(key)),
JsonWebSignatureAlg::Hs512 => Ok(Self::hs512(key)), JsonWebSignatureAlg::Hs512 => Ok(Self::hs512(key)),
_ => Err(InvalidAlgorithm { alg, key }), _ => Err(InvalidAlgorithm {
alg: alg.clone(),
key,
}),
} }
} }

View File

@ -166,9 +166,9 @@ impl<P> JsonWebKey<P> {
{ {
Ok(JsonWebKey { Ok(JsonWebKey {
parameters: mapper(&self.parameters)?, parameters: mapper(&self.parameters)?,
r#use: self.r#use, r#use: self.r#use.clone(),
key_ops: self.key_ops.clone(), key_ops: self.key_ops.clone(),
alg: self.alg, alg: self.alg.clone(),
kid: self.kid.clone(), kid: self.kid.clone(),
x5u: self.x5u.clone(), x5u: self.x5u.clone(),
x5c: self.x5c.clone(), x5c: self.x5c.clone(),
@ -183,9 +183,9 @@ impl<P> JsonWebKey<P> {
{ {
JsonWebKey { JsonWebKey {
parameters: mapper(&self.parameters), parameters: mapper(&self.parameters),
r#use: self.r#use, r#use: self.r#use.clone(),
key_ops: self.key_ops.clone(), key_ops: self.key_ops.clone(),
alg: self.alg, alg: self.alg.clone(),
kid: self.kid.clone(), kid: self.kid.clone(),
x5u: self.x5u.clone(), x5u: self.x5u.clone(),
x5c: self.x5c.clone(), x5c: self.x5c.clone(),
@ -195,7 +195,7 @@ impl<P> JsonWebKey<P> {
} }
#[must_use] #[must_use]
pub const fn with_use(mut self, value: JsonWebKeyUse) -> Self { pub fn with_use(mut self, value: JsonWebKeyUse) -> Self {
self.r#use = Some(value); self.r#use = Some(value);
self self
} }
@ -207,7 +207,7 @@ impl<P> JsonWebKey<P> {
} }
#[must_use] #[must_use]
pub const fn with_alg(mut self, alg: JsonWebSignatureAlg) -> Self { pub fn with_alg(mut self, alg: JsonWebSignatureAlg) -> Self {
self.alg = Some(alg); self.alg = Some(alg);
self self
} }
@ -219,8 +219,8 @@ impl<P> JsonWebKey<P> {
} }
#[must_use] #[must_use]
pub const fn alg(&self) -> Option<JsonWebSignatureAlg> { pub const fn alg(&self) -> Option<&JsonWebSignatureAlg> {
self.alg self.alg.as_ref()
} }
#[must_use] #[must_use]
@ -245,12 +245,12 @@ where
self.parameters.possible_algs() self.parameters.possible_algs()
} }
fn alg(&self) -> Option<JsonWebSignatureAlg> { fn alg(&self) -> Option<&JsonWebSignatureAlg> {
self.alg self.alg.as_ref()
} }
fn use_(&self) -> Option<JsonWebKeyUse> { fn use_(&self) -> Option<&JsonWebKeyUse> {
self.r#use self.r#use.as_ref()
} }
} }
@ -317,13 +317,13 @@ impl<P> JsonWebKeySet<P> {
/// Find a key for the given algorithm. Returns `None` if no suitable key /// Find a key for the given algorithm. Returns `None` if no suitable key
/// was found. /// was found.
#[must_use] #[must_use]
pub fn signing_key_for_algorithm(&self, alg: JsonWebSignatureAlg) -> Option<&JsonWebKey<P>> pub fn signing_key_for_algorithm(&self, alg: &JsonWebSignatureAlg) -> Option<&JsonWebKey<P>>
where where
P: ParametersInfo, P: ParametersInfo,
{ {
let constraints = ConstraintSet::new([ let constraints = ConstraintSet::new([
Constraint::alg(alg), Constraint::alg(alg),
Constraint::use_(mas_iana::jose::JsonWebKeyUse::Sig), Constraint::use_(&mas_iana::jose::JsonWebKeyUse::Sig),
]); ]);
self.find_key(&constraints) self.find_key(&constraints)
} }
@ -338,7 +338,7 @@ impl<P> JsonWebKeySet<P> {
.keys .keys
.iter() .iter()
.flat_map(|key| key.params().possible_algs()) .flat_map(|key| key.params().possible_algs())
.copied() .cloned()
.collect(); .collect();
algs.sort(); algs.sort();
algs.dedup(); algs.dedup();
@ -389,15 +389,15 @@ mod tests {
} }
let constraints = ConstraintSet::default() let constraints = ConstraintSet::default()
.use_(JsonWebKeyUse::Sig) .use_(&JsonWebKeyUse::Sig)
.kty(JsonWebKeyType::Rsa) .kty(&JsonWebKeyType::Rsa)
.alg(JsonWebSignatureAlg::Rs256); .alg(&JsonWebSignatureAlg::Rs256);
let candidates = constraints.filter(&jwks.keys); let candidates = constraints.filter(&jwks.keys);
assert_eq!(candidates.len(), 2); assert_eq!(candidates.len(), 2);
let constraints = ConstraintSet::default() let constraints = ConstraintSet::default()
.use_(JsonWebKeyUse::Sig) .use_(&JsonWebKeyUse::Sig)
.kty(JsonWebKeyType::Rsa) .kty(&JsonWebKeyType::Rsa)
.kid("03e84aed4ef4431014e8617567864c4efaaaede9"); .kid("03e84aed4ef4431014e8617567864c4efaaaede9");
let candidates = constraints.filter(&jwks.keys); let candidates = constraints.filter(&jwks.keys);
assert_eq!(candidates.len(), 1); assert_eq!(candidates.len(), 1);

View File

@ -335,6 +335,7 @@ impl ParametersInfo for EcPrivateParameters {
JsonWebKeyEcEllipticCurve::P384 => &[JsonWebSignatureAlg::Es384], JsonWebKeyEcEllipticCurve::P384 => &[JsonWebSignatureAlg::Es384],
JsonWebKeyEcEllipticCurve::P521 => &[JsonWebSignatureAlg::Es512], JsonWebKeyEcEllipticCurve::P521 => &[JsonWebSignatureAlg::Es512],
JsonWebKeyEcEllipticCurve::Secp256K1 => &[JsonWebSignatureAlg::Es256K], JsonWebKeyEcEllipticCurve::Secp256K1 => &[JsonWebSignatureAlg::Es256K],
_ => &[],
} }
} }
} }

View File

@ -137,8 +137,8 @@ impl EcPublicParameters {
Self { crv, x, y } Self { crv, x, y }
} }
pub const fn crv(&self) -> JsonWebKeyEcEllipticCurve { pub const fn crv(&self) -> &JsonWebKeyEcEllipticCurve {
self.crv &self.crv
} }
} }
@ -148,11 +148,12 @@ impl ParametersInfo for EcPublicParameters {
} }
fn possible_algs(&self) -> &[JsonWebSignatureAlg] { fn possible_algs(&self) -> &[JsonWebSignatureAlg] {
match self.crv { match &self.crv {
JsonWebKeyEcEllipticCurve::P256 => &[JsonWebSignatureAlg::Es256], JsonWebKeyEcEllipticCurve::P256 => &[JsonWebSignatureAlg::Es256],
JsonWebKeyEcEllipticCurve::P384 => &[JsonWebSignatureAlg::Es384], JsonWebKeyEcEllipticCurve::P384 => &[JsonWebSignatureAlg::Es384],
JsonWebKeyEcEllipticCurve::P521 => &[JsonWebSignatureAlg::Es512], JsonWebKeyEcEllipticCurve::P521 => &[JsonWebSignatureAlg::Es512],
JsonWebKeyEcEllipticCurve::Secp256K1 => &[JsonWebSignatureAlg::Es256K], JsonWebKeyEcEllipticCurve::Secp256K1 => &[JsonWebSignatureAlg::Es256K],
_ => &[],
} }
} }
} }
@ -182,8 +183,8 @@ impl OkpPublicParameters {
Self { crv, x } Self { crv, x }
} }
pub const fn crv(&self) -> JsonWebKeyOkpEllipticCurve { pub const fn crv(&self) -> &JsonWebKeyOkpEllipticCurve {
self.crv &self.crv
} }
} }
@ -360,7 +361,7 @@ mod ec_impls {
type Error = ecdsa::Error; type Error = ecdsa::Error;
fn try_from(value: &EcPublicParameters) -> Result<Self, Self::Error> { fn try_from(value: &EcPublicParameters) -> Result<Self, Self::Error> {
if value.crv() != C::CRV { if *value.crv() != C::CRV {
return Err(Self::Error::default()); return Err(Self::Error::default());
} }

View File

@ -82,8 +82,8 @@ impl JsonWebSignatureHeader {
} }
#[must_use] #[must_use]
pub const fn alg(&self) -> JsonWebSignatureAlg { pub const fn alg(&self) -> &JsonWebSignatureAlg {
self.alg &self.alg
} }
#[must_use] #[must_use]

View File

@ -70,7 +70,7 @@ macro_rules! asymetric_jwt_test {
fn validate_jwt() { fn validate_jwt() {
let jwt: Jwt<'_, Payload> = Jwt::try_from($jwt).unwrap(); let jwt: Jwt<'_, Payload> = Jwt::try_from($jwt).unwrap();
assert_eq!(jwt.payload().hello, "world"); assert_eq!(jwt.payload().hello, "world");
assert_eq!(jwt.header().alg(), JsonWebSignatureAlg::$alg); assert_eq!(*jwt.header().alg(), JsonWebSignatureAlg::$alg);
} }
#[test] #[test]
@ -105,7 +105,7 @@ macro_rules! asymetric_jwt_test {
let key = mas_jose::jwa::AsymmetricVerifyingKey::from_jwk_and_alg( let key = mas_jose::jwa::AsymmetricVerifyingKey::from_jwk_and_alg(
key.params(), key.params(),
JsonWebSignatureAlg::$alg, &JsonWebSignatureAlg::$alg,
) )
.unwrap(); .unwrap();
@ -118,12 +118,12 @@ macro_rules! asymetric_jwt_test {
let payload = Payload { let payload = Payload {
hello: "world".to_string(), hello: "world".to_string(),
}; };
let header = JsonWebSignatureHeader::new(alg); let header = JsonWebSignatureHeader::new(alg.clone());
let jwks = private_jwks(); let jwks = private_jwks();
let key = jwks.signing_key_for_algorithm(alg).unwrap(); let key = jwks.signing_key_for_algorithm(&alg).unwrap();
let key = mas_jose::jwa::AsymmetricSigningKey::from_jwk_and_alg(key.params(), alg) let key = mas_jose::jwa::AsymmetricSigningKey::from_jwk_and_alg(key.params(), &alg)
.unwrap(); .unwrap();
let jwt: Jwt<'_, Payload> = Jwt::sign(header, payload, &key).unwrap(); let jwt: Jwt<'_, Payload> = Jwt::sign(header, payload, &key).unwrap();
@ -133,7 +133,7 @@ macro_rules! asymetric_jwt_test {
let key = jwks.find_key(&jwt.header().into()).unwrap(); let key = jwks.find_key(&jwt.header().into()).unwrap();
let key = let key =
mas_jose::jwa::AsymmetricVerifyingKey::from_jwk_and_alg(key.params(), alg) mas_jose::jwa::AsymmetricVerifyingKey::from_jwk_and_alg(key.params(), &alg)
.unwrap(); .unwrap();
jwt.verify(&key).unwrap(); jwt.verify(&key).unwrap();
@ -155,14 +155,14 @@ macro_rules! symetric_jwt_test {
fn validate_jwt() { fn validate_jwt() {
let jwt: Jwt<'_, Payload> = Jwt::try_from($jwt).unwrap(); let jwt: Jwt<'_, Payload> = Jwt::try_from($jwt).unwrap();
assert_eq!(jwt.payload().hello, "world"); assert_eq!(jwt.payload().hello, "world");
assert_eq!(jwt.header().alg(), JsonWebSignatureAlg::$alg); assert_eq!(*jwt.header().alg(), JsonWebSignatureAlg::$alg);
} }
#[test] #[test]
fn verify_jwt() { fn verify_jwt() {
let jwt: Jwt<'_, Payload> = Jwt::try_from($jwt).unwrap(); let jwt: Jwt<'_, Payload> = Jwt::try_from($jwt).unwrap();
let key = let key =
mas_jose::jwa::SymmetricKey::new_for_alg(oct_key(), JsonWebSignatureAlg::$alg) mas_jose::jwa::SymmetricKey::new_for_alg(oct_key(), &JsonWebSignatureAlg::$alg)
.unwrap(); .unwrap();
jwt.verify(&key).unwrap(); jwt.verify(&key).unwrap();
} }
@ -173,9 +173,9 @@ macro_rules! symetric_jwt_test {
let payload = Payload { let payload = Payload {
hello: "world".to_string(), hello: "world".to_string(),
}; };
let header = JsonWebSignatureHeader::new(alg); let header = JsonWebSignatureHeader::new(alg.clone());
let key = mas_jose::jwa::SymmetricKey::new_for_alg(oct_key(), alg).unwrap(); let key = mas_jose::jwa::SymmetricKey::new_for_alg(oct_key(), &alg).unwrap();
let jwt: Jwt<'_, Payload> = Jwt::sign(header, payload, &key).unwrap(); let jwt: Jwt<'_, Payload> = Jwt::sign(header, payload, &key).unwrap();
let jwt: Jwt<'_, Payload> = Jwt::try_from(jwt.as_str()).unwrap(); let jwt: Jwt<'_, Payload> = Jwt::try_from(jwt.as_str()).unwrap();

View File

@ -415,7 +415,7 @@ impl PrivateKey {
/// Returns an error if the key is not suited for the selected algorithm /// Returns an error if the key is not suited for the selected algorithm
pub fn verifying_key_for_alg( pub fn verifying_key_for_alg(
&self, &self,
alg: JsonWebSignatureAlg, alg: &JsonWebSignatureAlg,
) -> Result<AsymmetricVerifyingKey, WrongAlgorithmError> { ) -> Result<AsymmetricVerifyingKey, WrongAlgorithmError> {
let key = match (self, alg) { let key = match (self, alg) {
(Self::Rsa(key), _) => { (Self::Rsa(key), _) => {
@ -469,7 +469,7 @@ impl PrivateKey {
/// Returns an error if the key is not suited for the selected algorithm /// Returns an error if the key is not suited for the selected algorithm
pub fn signing_key_for_alg( pub fn signing_key_for_alg(
&self, &self,
alg: JsonWebSignatureAlg, alg: &JsonWebSignatureAlg,
) -> Result<AsymmetricSigningKey, WrongAlgorithmError> { ) -> Result<AsymmetricSigningKey, WrongAlgorithmError> {
let key = match (self, alg) { let key = match (self, alg) {
(Self::Rsa(key), _) => { (Self::Rsa(key), _) => {

View File

@ -33,8 +33,8 @@ macro_rules! plain_test {
let algs = key.possible_algs(); let algs = key.possible_algs();
assert_ne!(algs.len(), 0); assert_ne!(algs.len(), 0);
for &alg in algs { for alg in algs {
let header = JsonWebSignatureHeader::new(alg); let header = JsonWebSignatureHeader::new(alg.clone());
let payload = "hello"; let payload = "hello";
let signer = key.signing_key_for_alg(alg).unwrap(); let signer = key.signing_key_for_alg(alg).unwrap();
let jwt = Jwt::sign(header, payload, &signer).unwrap(); let jwt = Jwt::sign(header, payload, &signer).unwrap();
@ -58,8 +58,8 @@ macro_rules! enc_test {
let algs = key.possible_algs(); let algs = key.possible_algs();
assert_ne!(algs.len(), 0); assert_ne!(algs.len(), 0);
for &alg in algs { for alg in algs {
let header = JsonWebSignatureHeader::new(alg); let header = JsonWebSignatureHeader::new(alg.clone());
let payload = "hello"; let payload = "hello";
let signer = key.signing_key_for_alg(alg).unwrap(); let signer = key.signing_key_for_alg(alg).unwrap();
let jwt = Jwt::sign(header, payload, &signer).unwrap(); let jwt = Jwt::sign(header, payload, &signer).unwrap();

View File

@ -33,7 +33,7 @@ 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( #[derive(
SerializeDisplay, DeserializeFromStr, Clone, Copy, PartialEq, Eq, Hash, Debug, Display, FromStr, SerializeDisplay, DeserializeFromStr, Clone, PartialEq, Eq, Hash, Debug, Display, FromStr,
)] )]
pub enum AuthenticationMethodOrAccessTokenType { pub enum AuthenticationMethodOrAccessTokenType {
/// An authentication method. /// An authentication method.
@ -49,9 +49,9 @@ impl AuthenticationMethodOrAccessTokenType {
/// Get the authentication method of this /// Get the authentication method of this
/// `AuthenticationMethodOrAccessTokenType`. /// `AuthenticationMethodOrAccessTokenType`.
#[must_use] #[must_use]
pub fn authentication_method(&self) -> Option<OAuthClientAuthenticationMethod> { pub fn authentication_method(&self) -> Option<&OAuthClientAuthenticationMethod> {
match self { match self {
Self::AuthenticationMethod(m) => Some(*m), Self::AuthenticationMethod(m) => Some(m),
Self::AccessTokenType(_) => None, Self::AccessTokenType(_) => None,
} }
} }
@ -59,10 +59,10 @@ impl AuthenticationMethodOrAccessTokenType {
/// Get the access token type of this /// Get the access token type of this
/// `AuthenticationMethodOrAccessTokenType`. /// `AuthenticationMethodOrAccessTokenType`.
#[must_use] #[must_use]
pub fn access_token_type(&self) -> Option<OAuthAccessTokenType> { pub fn access_token_type(&self) -> Option<&OAuthAccessTokenType> {
match self { match self {
Self::AuthenticationMethod(_) => None, Self::AuthenticationMethod(_) => None,
Self::AccessTokenType(t) => Some(*t), Self::AccessTokenType(t) => Some(t),
} }
} }
} }
@ -470,8 +470,14 @@ impl ProviderMetadata {
validate_signing_alg_values_supported( validate_signing_alg_values_supported(
"token_endpoint", "token_endpoint",
&metadata.token_endpoint_auth_signing_alg_values_supported, metadata
&metadata.token_endpoint_auth_methods_supported, .token_endpoint_auth_signing_alg_values_supported
.iter()
.flatten(),
metadata
.token_endpoint_auth_methods_supported
.iter()
.flatten(),
)?; )?;
if let Some(url) = &metadata.revocation_endpoint { if let Some(url) = &metadata.revocation_endpoint {
@ -480,8 +486,14 @@ impl ProviderMetadata {
validate_signing_alg_values_supported( validate_signing_alg_values_supported(
"revocation_endpoint", "revocation_endpoint",
&metadata.revocation_endpoint_auth_signing_alg_values_supported, metadata
&metadata.revocation_endpoint_auth_methods_supported, .revocation_endpoint_auth_signing_alg_values_supported
.iter()
.flatten(),
metadata
.revocation_endpoint_auth_methods_supported
.iter()
.flatten(),
)?; )?;
if let Some(url) = &metadata.introspection_endpoint { if let Some(url) = &metadata.introspection_endpoint {
@ -500,8 +512,11 @@ impl ProviderMetadata {
}); });
validate_signing_alg_values_supported( validate_signing_alg_values_supported(
"introspection_endpoint", "introspection_endpoint",
&metadata.introspection_endpoint_auth_signing_alg_values_supported, metadata
&introspection_methods, .introspection_endpoint_auth_signing_alg_values_supported
.iter()
.flatten(),
introspection_methods.into_iter().flatten(),
)?; )?;
if let Some(url) = &metadata.userinfo_endpoint { if let Some(url) = &metadata.userinfo_endpoint {
@ -957,24 +972,32 @@ fn validate_url(
/// - The algorithm values must not contain `none`, /// - The algorithm values must not contain `none`,
/// - If the `client_secret_jwt` or `private_key_jwt` authentication methods are /// - If the `client_secret_jwt` or `private_key_jwt` authentication methods are
/// supported, the values must be present. /// supported, the values must be present.
fn validate_signing_alg_values_supported( fn validate_signing_alg_values_supported<'a>(
endpoint: &'static str, endpoint: &'static str,
values: &Option<Vec<JsonWebSignatureAlg>>, values: impl Iterator<Item = &'a JsonWebSignatureAlg>,
methods: &Option<Vec<OAuthClientAuthenticationMethod>>, mut methods: impl Iterator<Item = &'a OAuthClientAuthenticationMethod>,
) -> Result<(), ProviderMetadataVerificationError> { ) -> Result<(), ProviderMetadataVerificationError> {
if let Some(values) = values { let mut no_values = true;
if values.contains(&JsonWebSignatureAlg::None) {
for value in values {
if *value == JsonWebSignatureAlg::None {
return Err(ProviderMetadataVerificationError::SigningAlgValuesWithNone( return Err(ProviderMetadataVerificationError::SigningAlgValuesWithNone(
endpoint, endpoint,
)); ));
} }
} else if methods.iter().flatten().any(|method| {
matches!( no_values = false;
method, }
OAuthClientAuthenticationMethod::ClientSecretJwt
| OAuthClientAuthenticationMethod::PrivateKeyJwt if no_values
) && methods.any(|method| {
}) { matches!(
method,
OAuthClientAuthenticationMethod::ClientSecretJwt
| OAuthClientAuthenticationMethod::PrivateKeyJwt
)
})
{
return Err(ProviderMetadataVerificationError::MissingAuthSigningAlgValues(endpoint)); return Err(ProviderMetadataVerificationError::MissingAuthSigningAlgValues(endpoint));
} }

View File

@ -33,6 +33,9 @@ pub enum CodeChallengeError {
#[error("challenge verification failed")] #[error("challenge verification failed")]
VerificationFailed, VerificationFailed,
#[error("unknown challenge method")]
UnknownChallengeMethod,
} }
fn validate_verifier(verifier: &str) -> Result<(), CodeChallengeError> { fn validate_verifier(verifier: &str) -> Result<(), CodeChallengeError> {
@ -61,7 +64,7 @@ pub trait CodeChallengeMethodExt {
/// ///
/// Returns an error if the verifier did not adhere to the rules defined by /// Returns an error if the verifier did not adhere to the rules defined by
/// the RFC in terms of length and allowed characters /// the RFC in terms of length and allowed characters
fn compute_challenge(self, verifier: &str) -> Result<Cow<'_, str>, CodeChallengeError>; fn compute_challenge<'a>(&self, verifier: &'a str) -> Result<Cow<'a, str>, CodeChallengeError>;
/// Verify that a given verifier is valid for the given challenge /// Verify that a given verifier is valid for the given challenge
/// ///
@ -70,7 +73,7 @@ pub trait CodeChallengeMethodExt {
/// Returns an error if the verifier did not match the challenge, or if the /// Returns an error if the verifier did not match the challenge, or if the
/// verifier did not adhere to the rules defined by the RFC in terms of /// verifier did not adhere to the rules defined by the RFC in terms of
/// length and allowed characters /// length and allowed characters
fn verify(self, challenge: &str, verifier: &str) -> Result<(), CodeChallengeError> fn verify(&self, challenge: &str, verifier: &str) -> Result<(), CodeChallengeError>
where where
Self: Sized, Self: Sized,
{ {
@ -83,7 +86,7 @@ pub trait CodeChallengeMethodExt {
} }
impl CodeChallengeMethodExt for PkceCodeChallengeMethod { impl CodeChallengeMethodExt for PkceCodeChallengeMethod {
fn compute_challenge(self, verifier: &str) -> Result<Cow<'_, str>, CodeChallengeError> { fn compute_challenge<'a>(&self, verifier: &'a str) -> Result<Cow<'a, str>, CodeChallengeError> {
validate_verifier(verifier)?; validate_verifier(verifier)?;
let challenge = match self { let challenge = match self {
@ -95,6 +98,7 @@ impl CodeChallengeMethodExt for PkceCodeChallengeMethod {
let verifier = BASE64URL_NOPAD.encode(&hash); let verifier = BASE64URL_NOPAD.encode(&hash);
verifier.into() verifier.into()
} }
_ => return Err(CodeChallengeError::UnknownChallengeMethod),
}; };
Ok(challenge) Ok(challenge)

View File

@ -42,13 +42,13 @@ pub const DEFAULT_GRANT_TYPES: &[GrantType] = &[GrantType::AuthorizationCode];
pub const DEFAULT_APPLICATION_TYPE: ApplicationType = ApplicationType::Web; pub const DEFAULT_APPLICATION_TYPE: ApplicationType = ApplicationType::Web;
pub const DEFAULT_TOKEN_AUTH_METHOD: OAuthClientAuthenticationMethod = pub const DEFAULT_TOKEN_AUTH_METHOD: &OAuthClientAuthenticationMethod =
OAuthClientAuthenticationMethod::ClientSecretBasic; &OAuthClientAuthenticationMethod::ClientSecretBasic;
pub const DEFAULT_SIGNING_ALGORITHM: JsonWebSignatureAlg = JsonWebSignatureAlg::Rs256; pub const DEFAULT_SIGNING_ALGORITHM: &JsonWebSignatureAlg = &JsonWebSignatureAlg::Rs256;
pub const DEFAULT_ENCRYPTION_ENC_ALGORITHM: JsonWebEncryptionEnc = pub const DEFAULT_ENCRYPTION_ENC_ALGORITHM: &JsonWebEncryptionEnc =
JsonWebEncryptionEnc::A128CbcHs256; &JsonWebEncryptionEnc::A128CbcHs256;
/// A collection of localized variants. /// A collection of localized variants.
/// ///
@ -463,7 +463,7 @@ impl ClientMetadata {
)); ));
} }
if self.token_endpoint_auth_method() == OAuthClientAuthenticationMethod::PrivateKeyJwt if *self.token_endpoint_auth_method() == OAuthClientAuthenticationMethod::PrivateKeyJwt
&& self.jwks_uri.is_none() && self.jwks_uri.is_none()
&& self.jwks.is_none() && self.jwks.is_none()
{ {
@ -486,26 +486,26 @@ impl ClientMetadata {
)); ));
} }
if self.id_token_signed_response_alg() == JsonWebSignatureAlg::None if *self.id_token_signed_response_alg() == JsonWebSignatureAlg::None
&& response_types.iter().any(ResponseType::has_id_token) && response_types.iter().any(ResponseType::has_id_token)
{ {
return Err(ClientMetadataVerificationError::IdTokenSigningAlgNone); return Err(ClientMetadataVerificationError::IdTokenSigningAlgNone);
} }
if self.id_token_encrypted_response_enc.is_some() { if self.id_token_encrypted_response_enc.is_some() {
self.id_token_encrypted_response_alg.ok_or( self.id_token_encrypted_response_alg.as_ref().ok_or(
ClientMetadataVerificationError::MissingEncryptionAlg("id_token"), ClientMetadataVerificationError::MissingEncryptionAlg("id_token"),
)?; )?;
} }
if self.userinfo_encrypted_response_enc.is_some() { if self.userinfo_encrypted_response_enc.is_some() {
self.userinfo_encrypted_response_alg.ok_or( self.userinfo_encrypted_response_alg.as_ref().ok_or(
ClientMetadataVerificationError::MissingEncryptionAlg("userinfo"), ClientMetadataVerificationError::MissingEncryptionAlg("userinfo"),
)?; )?;
} }
if self.request_object_encryption_enc.is_some() { if self.request_object_encryption_enc.is_some() {
self.request_object_encryption_alg.ok_or( self.request_object_encryption_alg.as_ref().ok_or(
ClientMetadataVerificationError::MissingEncryptionAlg("request_object"), ClientMetadataVerificationError::MissingEncryptionAlg("request_object"),
)?; )?;
} }
@ -522,7 +522,7 @@ impl ClientMetadata {
} }
if self.introspection_encrypted_response_enc.is_some() { if self.introspection_encrypted_response_enc.is_some() {
self.introspection_encrypted_response_alg.ok_or( self.introspection_encrypted_response_alg.as_ref().ok_or(
ClientMetadataVerificationError::MissingEncryptionAlg("introspection"), ClientMetadataVerificationError::MissingEncryptionAlg("introspection"),
)?; )?;
} }
@ -542,9 +542,12 @@ impl ClientMetadata {
/// [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
#[must_use] #[must_use]
pub fn response_types(&self) -> Vec<ResponseType> { pub fn response_types(&self) -> Vec<ResponseType> {
self.response_types self.response_types.clone().unwrap_or_else(|| {
.clone() DEFAULT_RESPONSE_TYPES
.unwrap_or_else(|| DEFAULT_RESPONSE_TYPES.map(ResponseType::from).into()) .into_iter()
.filter_map(|t| ResponseType::try_from(t).ok())
.collect()
})
} }
/// Array of [OAuth 2.0 `grant_type` values] that the client can use at the /// Array of [OAuth 2.0 `grant_type` values] that the client can use at the
@ -578,8 +581,9 @@ impl ClientMetadata {
/// ///
/// [token endpoint]: https://www.rfc-editor.org/rfc/rfc6749.html#section-3.2 /// [token endpoint]: https://www.rfc-editor.org/rfc/rfc6749.html#section-3.2
#[must_use] #[must_use]
pub fn token_endpoint_auth_method(&self) -> OAuthClientAuthenticationMethod { pub fn token_endpoint_auth_method(&self) -> &OAuthClientAuthenticationMethod {
self.token_endpoint_auth_method self.token_endpoint_auth_method
.as_ref()
.unwrap_or(DEFAULT_TOKEN_AUTH_METHOD) .unwrap_or(DEFAULT_TOKEN_AUTH_METHOD)
} }
@ -594,8 +598,9 @@ impl ClientMetadata {
/// ///
/// [JWS]: http://tools.ietf.org/html/draft-ietf-jose-json-web-signature /// [JWS]: http://tools.ietf.org/html/draft-ietf-jose-json-web-signature
#[must_use] #[must_use]
pub fn id_token_signed_response_alg(&self) -> JsonWebSignatureAlg { pub fn id_token_signed_response_alg(&self) -> &JsonWebSignatureAlg {
self.id_token_signed_response_alg self.id_token_signed_response_alg
.as_ref()
.unwrap_or(DEFAULT_SIGNING_ALGORITHM) .unwrap_or(DEFAULT_SIGNING_ALGORITHM)
} }
@ -610,11 +615,12 @@ impl ClientMetadata {
#[must_use] #[must_use]
pub fn id_token_encrypted_response( pub fn id_token_encrypted_response(
&self, &self,
) -> Option<(JsonWebEncryptionAlg, JsonWebEncryptionEnc)> { ) -> Option<(&JsonWebEncryptionAlg, &JsonWebEncryptionEnc)> {
self.id_token_encrypted_response_alg.map(|alg| { self.id_token_encrypted_response_alg.as_ref().map(|alg| {
( (
alg, alg,
self.id_token_encrypted_response_enc self.id_token_encrypted_response_enc
.as_ref()
.unwrap_or(DEFAULT_ENCRYPTION_ENC_ALGORITHM), .unwrap_or(DEFAULT_ENCRYPTION_ENC_ALGORITHM),
) )
}) })
@ -631,11 +637,12 @@ impl ClientMetadata {
#[must_use] #[must_use]
pub fn userinfo_encrypted_response( pub fn userinfo_encrypted_response(
&self, &self,
) -> Option<(JsonWebEncryptionAlg, JsonWebEncryptionEnc)> { ) -> Option<(&JsonWebEncryptionAlg, &JsonWebEncryptionEnc)> {
self.userinfo_encrypted_response_alg.map(|alg| { self.userinfo_encrypted_response_alg.as_ref().map(|alg| {
( (
alg, alg,
self.userinfo_encrypted_response_enc self.userinfo_encrypted_response_enc
.as_ref()
.unwrap_or(DEFAULT_ENCRYPTION_ENC_ALGORITHM), .unwrap_or(DEFAULT_ENCRYPTION_ENC_ALGORITHM),
) )
}) })
@ -652,11 +659,12 @@ impl ClientMetadata {
#[must_use] #[must_use]
pub fn request_object_encryption( pub fn request_object_encryption(
&self, &self,
) -> Option<(JsonWebEncryptionAlg, JsonWebEncryptionEnc)> { ) -> Option<(&JsonWebEncryptionAlg, &JsonWebEncryptionEnc)> {
self.request_object_encryption_alg.map(|alg| { self.request_object_encryption_alg.as_ref().map(|alg| {
( (
alg, alg,
self.request_object_encryption_enc self.request_object_encryption_enc
.as_ref()
.unwrap_or(DEFAULT_ENCRYPTION_ENC_ALGORITHM), .unwrap_or(DEFAULT_ENCRYPTION_ENC_ALGORITHM),
) )
}) })
@ -705,14 +713,17 @@ impl ClientMetadata {
#[must_use] #[must_use]
pub fn introspection_encrypted_response( pub fn introspection_encrypted_response(
&self, &self,
) -> Option<(JsonWebEncryptionAlg, JsonWebEncryptionEnc)> { ) -> Option<(&JsonWebEncryptionAlg, &JsonWebEncryptionEnc)> {
self.introspection_encrypted_response_alg.map(|alg| { self.introspection_encrypted_response_alg
( .as_ref()
alg, .map(|alg| {
self.introspection_encrypted_response_enc (
.unwrap_or(DEFAULT_ENCRYPTION_ENC_ALGORITHM), alg,
) self.introspection_encrypted_response_enc
}) .as_ref()
.unwrap_or(DEFAULT_ENCRYPTION_ENC_ALGORITHM),
)
})
} }
} }

View File

@ -332,10 +332,10 @@ pub async fn insert_client(
tos_uri: Option<&Url>, tos_uri: Option<&Url>,
jwks_uri: Option<&Url>, jwks_uri: Option<&Url>,
jwks: Option<&PublicJsonWebKeySet>, jwks: Option<&PublicJsonWebKeySet>,
id_token_signed_response_alg: Option<JsonWebSignatureAlg>, id_token_signed_response_alg: Option<&JsonWebSignatureAlg>,
userinfo_signed_response_alg: Option<JsonWebSignatureAlg>, userinfo_signed_response_alg: Option<&JsonWebSignatureAlg>,
token_endpoint_auth_method: Option<OAuthClientAuthenticationMethod>, token_endpoint_auth_method: Option<&OAuthClientAuthenticationMethod>,
token_endpoint_auth_signing_alg: Option<JsonWebSignatureAlg>, token_endpoint_auth_signing_alg: Option<&JsonWebSignatureAlg>,
initiate_login_uri: Option<&Url>, initiate_login_uri: Option<&Url>,
) -> Result<(), sqlx::Error> { ) -> Result<(), sqlx::Error> {
let response_types: Vec<String> = response_types.iter().map(ToString::to_string).collect(); let response_types: Vec<String> = response_types.iter().map(ToString::to_string).collect();
@ -347,10 +347,10 @@ pub async fn insert_client(
let tos_uri = tos_uri.map(Url::as_str); let tos_uri = tos_uri.map(Url::as_str);
let jwks = jwks.map(serde_json::to_value).transpose().unwrap(); // TODO let jwks = jwks.map(serde_json::to_value).transpose().unwrap(); // TODO
let jwks_uri = jwks_uri.map(Url::as_str); let jwks_uri = jwks_uri.map(Url::as_str);
let id_token_signed_response_alg = id_token_signed_response_alg.map(|v| v.to_string()); let id_token_signed_response_alg = id_token_signed_response_alg.map(ToString::to_string);
let userinfo_signed_response_alg = userinfo_signed_response_alg.map(|v| v.to_string()); let userinfo_signed_response_alg = userinfo_signed_response_alg.map(ToString::to_string);
let token_endpoint_auth_method = token_endpoint_auth_method.map(|v| v.to_string()); let token_endpoint_auth_method = token_endpoint_auth_method.map(ToString::to_string);
let token_endpoint_auth_signing_alg = token_endpoint_auth_signing_alg.map(|v| v.to_string()); let token_endpoint_auth_signing_alg = token_endpoint_auth_signing_alg.map(ToString::to_string);
let initiate_login_uri = initiate_login_uri.map(Url::as_str); let initiate_login_uri = initiate_login_uri.map(Url::as_str);
let id = sqlx::query_scalar!( let id = sqlx::query_scalar!(