diff --git a/jwt-authorizer/src/authorizer.rs b/jwt-authorizer/src/authorizer.rs index 00d0840..1465590 100644 --- a/jwt-authorizer/src/authorizer.rs +++ b/jwt-authorizer/src/authorizer.rs @@ -228,7 +228,7 @@ where let header = decode_header(token)?; // TODO: (optimisation) build & store jwt_validation in key data, to avoid rebuilding it for each check let val_key = self.key_source.get_key(header).await?; - let jwt_validation = &self.validation.to_jwt_validation(val_key.algs.clone()); + let jwt_validation = &self.validation.to_jwt_validation(&val_key.algs); let token_data = decode::(token, &val_key.key, jwt_validation)?; if let Some(ref checker) = self.claims_checker { diff --git a/jwt-authorizer/src/validation.rs b/jwt-authorizer/src/validation.rs index 8f0fb43..97c488b 100644 --- a/jwt-authorizer/src/validation.rs +++ b/jwt-authorizer/src/validation.rs @@ -30,6 +30,11 @@ pub struct Validation { /// /// Defaults to true. pub validate_signature: bool, + + /// Accepted algorithms + /// + /// If empty anly the algorithms matching key will be authorized + pub algs: Vec, } impl Validation { @@ -82,7 +87,17 @@ impl Validation { self } - pub(crate) fn to_jwt_validation(&self, alg: Vec) -> jsonwebtoken::Validation { + /// Authorized algorithms. + /// + /// If no algs are supplied default algs for the key will be used + /// (example for a EC key, algs = [ES256, ES384]). + pub fn algs(mut self, algs: Vec) -> Self { + self.algs = algs; + + self + } + + pub(crate) fn to_jwt_validation(&self, default_algs: &Vec) -> jsonwebtoken::Validation { let required_claims = if self.validate_exp { let mut claims = HashSet::with_capacity(1); claims.insert("exp".to_owned()); @@ -103,7 +118,11 @@ impl Validation { jwt_validation.iss = iss; jwt_validation.aud = aud; jwt_validation.sub = None; - jwt_validation.algorithms = alg; + jwt_validation.algorithms = if self.algs.is_empty() { + default_algs.clone() + } else { + self.algs.clone() + }; if !self.validate_signature { jwt_validation.insecure_disable_signature_validation(); } @@ -124,6 +143,7 @@ impl Default for Validation { aud: None, validate_signature: true, + algs: vec![], } } } diff --git a/jwt-authorizer/tests/tests.rs b/jwt-authorizer/tests/tests.rs index 8210050..75b3d5b 100644 --- a/jwt-authorizer/tests/tests.rs +++ b/jwt-authorizer/tests/tests.rs @@ -12,6 +12,7 @@ mod tests { BoxError, Router, }; use http::{header, HeaderValue}; + use jsonwebtoken::Algorithm; use jwt_authorizer::{ authorizer::Authorizer, layer::{AuthorizationLayer, JwtSource}, @@ -374,6 +375,27 @@ mod tests { assert_eq!(response.status(), StatusCode::OK); } + #[tokio::test] + async fn validate_algs() { + // OK + let response = make_proteced_request( + JwtAuthorizer::from_rsa_pem("../config/rsa-public1.pem") + .validation(Validation::new().algs(vec![Algorithm::RS256, Algorithm::RS384])), + common::JWT_RSA1_OK, + ) + .await; + assert_eq!(response.status(), StatusCode::OK); + + // NOK - Invalid Alg + let response = make_proteced_request( + JwtAuthorizer::from_rsa_pem("../config/rsa-public1.pem") + .validation(Validation::new().algs(vec![Algorithm::RS512])), + common::JWT_RSA1_OK, + ) + .await; + assert_eq!(response.status(), StatusCode::OK); + } + // -------------------- // jwt_source // ---------------------