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
Add variants for unknown values on mas-iana types
Remove the Copy derive and mark enums as non-exhaustive.
This commit is contained in:
committed by
Quentin Gliech
parent
9e3b3567b2
commit
80d317f23c
@ -33,7 +33,7 @@ use crate::{
|
||||
/// An enum for types that accept either an [`OAuthClientAuthenticationMethod`]
|
||||
/// or an [`OAuthAccessTokenType`].
|
||||
#[derive(
|
||||
SerializeDisplay, DeserializeFromStr, Clone, Copy, PartialEq, Eq, Hash, Debug, Display, FromStr,
|
||||
SerializeDisplay, DeserializeFromStr, Clone, PartialEq, Eq, Hash, Debug, Display, FromStr,
|
||||
)]
|
||||
pub enum AuthenticationMethodOrAccessTokenType {
|
||||
/// An authentication method.
|
||||
@ -49,9 +49,9 @@ impl AuthenticationMethodOrAccessTokenType {
|
||||
/// Get the authentication method of this
|
||||
/// `AuthenticationMethodOrAccessTokenType`.
|
||||
#[must_use]
|
||||
pub fn authentication_method(&self) -> Option<OAuthClientAuthenticationMethod> {
|
||||
pub fn authentication_method(&self) -> Option<&OAuthClientAuthenticationMethod> {
|
||||
match self {
|
||||
Self::AuthenticationMethod(m) => Some(*m),
|
||||
Self::AuthenticationMethod(m) => Some(m),
|
||||
Self::AccessTokenType(_) => None,
|
||||
}
|
||||
}
|
||||
@ -59,10 +59,10 @@ impl AuthenticationMethodOrAccessTokenType {
|
||||
/// Get the access token type of this
|
||||
/// `AuthenticationMethodOrAccessTokenType`.
|
||||
#[must_use]
|
||||
pub fn access_token_type(&self) -> Option<OAuthAccessTokenType> {
|
||||
pub fn access_token_type(&self) -> Option<&OAuthAccessTokenType> {
|
||||
match self {
|
||||
Self::AuthenticationMethod(_) => None,
|
||||
Self::AccessTokenType(t) => Some(*t),
|
||||
Self::AccessTokenType(t) => Some(t),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -470,8 +470,14 @@ impl ProviderMetadata {
|
||||
|
||||
validate_signing_alg_values_supported(
|
||||
"token_endpoint",
|
||||
&metadata.token_endpoint_auth_signing_alg_values_supported,
|
||||
&metadata.token_endpoint_auth_methods_supported,
|
||||
metadata
|
||||
.token_endpoint_auth_signing_alg_values_supported
|
||||
.iter()
|
||||
.flatten(),
|
||||
metadata
|
||||
.token_endpoint_auth_methods_supported
|
||||
.iter()
|
||||
.flatten(),
|
||||
)?;
|
||||
|
||||
if let Some(url) = &metadata.revocation_endpoint {
|
||||
@ -480,8 +486,14 @@ impl ProviderMetadata {
|
||||
|
||||
validate_signing_alg_values_supported(
|
||||
"revocation_endpoint",
|
||||
&metadata.revocation_endpoint_auth_signing_alg_values_supported,
|
||||
&metadata.revocation_endpoint_auth_methods_supported,
|
||||
metadata
|
||||
.revocation_endpoint_auth_signing_alg_values_supported
|
||||
.iter()
|
||||
.flatten(),
|
||||
metadata
|
||||
.revocation_endpoint_auth_methods_supported
|
||||
.iter()
|
||||
.flatten(),
|
||||
)?;
|
||||
|
||||
if let Some(url) = &metadata.introspection_endpoint {
|
||||
@ -500,8 +512,11 @@ impl ProviderMetadata {
|
||||
});
|
||||
validate_signing_alg_values_supported(
|
||||
"introspection_endpoint",
|
||||
&metadata.introspection_endpoint_auth_signing_alg_values_supported,
|
||||
&introspection_methods,
|
||||
metadata
|
||||
.introspection_endpoint_auth_signing_alg_values_supported
|
||||
.iter()
|
||||
.flatten(),
|
||||
introspection_methods.into_iter().flatten(),
|
||||
)?;
|
||||
|
||||
if let Some(url) = &metadata.userinfo_endpoint {
|
||||
@ -957,24 +972,32 @@ fn validate_url(
|
||||
/// - The algorithm values must not contain `none`,
|
||||
/// - If the `client_secret_jwt` or `private_key_jwt` authentication methods are
|
||||
/// supported, the values must be present.
|
||||
fn validate_signing_alg_values_supported(
|
||||
fn validate_signing_alg_values_supported<'a>(
|
||||
endpoint: &'static str,
|
||||
values: &Option<Vec<JsonWebSignatureAlg>>,
|
||||
methods: &Option<Vec<OAuthClientAuthenticationMethod>>,
|
||||
values: impl Iterator<Item = &'a JsonWebSignatureAlg>,
|
||||
mut methods: impl Iterator<Item = &'a OAuthClientAuthenticationMethod>,
|
||||
) -> Result<(), ProviderMetadataVerificationError> {
|
||||
if let Some(values) = values {
|
||||
if values.contains(&JsonWebSignatureAlg::None) {
|
||||
let mut no_values = true;
|
||||
|
||||
for value in values {
|
||||
if *value == JsonWebSignatureAlg::None {
|
||||
return Err(ProviderMetadataVerificationError::SigningAlgValuesWithNone(
|
||||
endpoint,
|
||||
));
|
||||
}
|
||||
} else if methods.iter().flatten().any(|method| {
|
||||
matches!(
|
||||
method,
|
||||
OAuthClientAuthenticationMethod::ClientSecretJwt
|
||||
| OAuthClientAuthenticationMethod::PrivateKeyJwt
|
||||
)
|
||||
}) {
|
||||
|
||||
no_values = false;
|
||||
}
|
||||
|
||||
if no_values
|
||||
&& methods.any(|method| {
|
||||
matches!(
|
||||
method,
|
||||
OAuthClientAuthenticationMethod::ClientSecretJwt
|
||||
| OAuthClientAuthenticationMethod::PrivateKeyJwt
|
||||
)
|
||||
})
|
||||
{
|
||||
return Err(ProviderMetadataVerificationError::MissingAuthSigningAlgValues(endpoint));
|
||||
}
|
||||
|
||||
|
@ -33,6 +33,9 @@ pub enum CodeChallengeError {
|
||||
|
||||
#[error("challenge verification failed")]
|
||||
VerificationFailed,
|
||||
|
||||
#[error("unknown challenge method")]
|
||||
UnknownChallengeMethod,
|
||||
}
|
||||
|
||||
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
|
||||
/// 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
|
||||
///
|
||||
@ -70,7 +73,7 @@ pub trait CodeChallengeMethodExt {
|
||||
/// 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
|
||||
/// length and allowed characters
|
||||
fn verify(self, challenge: &str, verifier: &str) -> Result<(), CodeChallengeError>
|
||||
fn verify(&self, challenge: &str, verifier: &str) -> Result<(), CodeChallengeError>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
@ -83,7 +86,7 @@ pub trait CodeChallengeMethodExt {
|
||||
}
|
||||
|
||||
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)?;
|
||||
|
||||
let challenge = match self {
|
||||
@ -95,6 +98,7 @@ impl CodeChallengeMethodExt for PkceCodeChallengeMethod {
|
||||
let verifier = BASE64URL_NOPAD.encode(&hash);
|
||||
verifier.into()
|
||||
}
|
||||
_ => return Err(CodeChallengeError::UnknownChallengeMethod),
|
||||
};
|
||||
|
||||
Ok(challenge)
|
||||
|
@ -42,13 +42,13 @@ pub const DEFAULT_GRANT_TYPES: &[GrantType] = &[GrantType::AuthorizationCode];
|
||||
|
||||
pub const DEFAULT_APPLICATION_TYPE: ApplicationType = ApplicationType::Web;
|
||||
|
||||
pub const DEFAULT_TOKEN_AUTH_METHOD: OAuthClientAuthenticationMethod =
|
||||
OAuthClientAuthenticationMethod::ClientSecretBasic;
|
||||
pub const DEFAULT_TOKEN_AUTH_METHOD: &OAuthClientAuthenticationMethod =
|
||||
&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 =
|
||||
JsonWebEncryptionEnc::A128CbcHs256;
|
||||
pub const DEFAULT_ENCRYPTION_ENC_ALGORITHM: &JsonWebEncryptionEnc =
|
||||
&JsonWebEncryptionEnc::A128CbcHs256;
|
||||
|
||||
/// 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.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)
|
||||
{
|
||||
return Err(ClientMetadataVerificationError::IdTokenSigningAlgNone);
|
||||
}
|
||||
|
||||
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"),
|
||||
)?;
|
||||
}
|
||||
|
||||
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"),
|
||||
)?;
|
||||
}
|
||||
|
||||
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"),
|
||||
)?;
|
||||
}
|
||||
@ -522,7 +522,7 @@ impl ClientMetadata {
|
||||
}
|
||||
|
||||
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"),
|
||||
)?;
|
||||
}
|
||||
@ -542,9 +542,12 @@ impl ClientMetadata {
|
||||
/// [authorization endpoint]: https://www.rfc-editor.org/rfc/rfc6749.html#section-3.1
|
||||
#[must_use]
|
||||
pub fn response_types(&self) -> Vec<ResponseType> {
|
||||
self.response_types
|
||||
.clone()
|
||||
.unwrap_or_else(|| DEFAULT_RESPONSE_TYPES.map(ResponseType::from).into())
|
||||
self.response_types.clone().unwrap_or_else(|| {
|
||||
DEFAULT_RESPONSE_TYPES
|
||||
.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
|
||||
@ -578,8 +581,9 @@ impl ClientMetadata {
|
||||
///
|
||||
/// [token endpoint]: https://www.rfc-editor.org/rfc/rfc6749.html#section-3.2
|
||||
#[must_use]
|
||||
pub fn token_endpoint_auth_method(&self) -> OAuthClientAuthenticationMethod {
|
||||
pub fn token_endpoint_auth_method(&self) -> &OAuthClientAuthenticationMethod {
|
||||
self.token_endpoint_auth_method
|
||||
.as_ref()
|
||||
.unwrap_or(DEFAULT_TOKEN_AUTH_METHOD)
|
||||
}
|
||||
|
||||
@ -594,8 +598,9 @@ impl ClientMetadata {
|
||||
///
|
||||
/// [JWS]: http://tools.ietf.org/html/draft-ietf-jose-json-web-signature
|
||||
#[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
|
||||
.as_ref()
|
||||
.unwrap_or(DEFAULT_SIGNING_ALGORITHM)
|
||||
}
|
||||
|
||||
@ -610,11 +615,12 @@ impl ClientMetadata {
|
||||
#[must_use]
|
||||
pub fn id_token_encrypted_response(
|
||||
&self,
|
||||
) -> Option<(JsonWebEncryptionAlg, JsonWebEncryptionEnc)> {
|
||||
self.id_token_encrypted_response_alg.map(|alg| {
|
||||
) -> Option<(&JsonWebEncryptionAlg, &JsonWebEncryptionEnc)> {
|
||||
self.id_token_encrypted_response_alg.as_ref().map(|alg| {
|
||||
(
|
||||
alg,
|
||||
self.id_token_encrypted_response_enc
|
||||
.as_ref()
|
||||
.unwrap_or(DEFAULT_ENCRYPTION_ENC_ALGORITHM),
|
||||
)
|
||||
})
|
||||
@ -631,11 +637,12 @@ impl ClientMetadata {
|
||||
#[must_use]
|
||||
pub fn userinfo_encrypted_response(
|
||||
&self,
|
||||
) -> Option<(JsonWebEncryptionAlg, JsonWebEncryptionEnc)> {
|
||||
self.userinfo_encrypted_response_alg.map(|alg| {
|
||||
) -> Option<(&JsonWebEncryptionAlg, &JsonWebEncryptionEnc)> {
|
||||
self.userinfo_encrypted_response_alg.as_ref().map(|alg| {
|
||||
(
|
||||
alg,
|
||||
self.userinfo_encrypted_response_enc
|
||||
.as_ref()
|
||||
.unwrap_or(DEFAULT_ENCRYPTION_ENC_ALGORITHM),
|
||||
)
|
||||
})
|
||||
@ -652,11 +659,12 @@ impl ClientMetadata {
|
||||
#[must_use]
|
||||
pub fn request_object_encryption(
|
||||
&self,
|
||||
) -> Option<(JsonWebEncryptionAlg, JsonWebEncryptionEnc)> {
|
||||
self.request_object_encryption_alg.map(|alg| {
|
||||
) -> Option<(&JsonWebEncryptionAlg, &JsonWebEncryptionEnc)> {
|
||||
self.request_object_encryption_alg.as_ref().map(|alg| {
|
||||
(
|
||||
alg,
|
||||
self.request_object_encryption_enc
|
||||
.as_ref()
|
||||
.unwrap_or(DEFAULT_ENCRYPTION_ENC_ALGORITHM),
|
||||
)
|
||||
})
|
||||
@ -705,14 +713,17 @@ impl ClientMetadata {
|
||||
#[must_use]
|
||||
pub fn introspection_encrypted_response(
|
||||
&self,
|
||||
) -> Option<(JsonWebEncryptionAlg, JsonWebEncryptionEnc)> {
|
||||
self.introspection_encrypted_response_alg.map(|alg| {
|
||||
(
|
||||
alg,
|
||||
self.introspection_encrypted_response_enc
|
||||
.unwrap_or(DEFAULT_ENCRYPTION_ENC_ALGORITHM),
|
||||
)
|
||||
})
|
||||
) -> Option<(&JsonWebEncryptionAlg, &JsonWebEncryptionEnc)> {
|
||||
self.introspection_encrypted_response_alg
|
||||
.as_ref()
|
||||
.map(|alg| {
|
||||
(
|
||||
alg,
|
||||
self.introspection_encrypted_response_enc
|
||||
.as_ref()
|
||||
.unwrap_or(DEFAULT_ENCRYPTION_ENC_ALGORITHM),
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user