diff --git a/Cargo.toml b/Cargo.toml index 8058205..442e3c4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,6 +15,6 @@ serde_json = "1.0" serde_derive = "1.0" serde = "1.0" ring = { version = "0.12.0", features = ["rsa_signing", "dev_urandom_fallback"] } -base64 = "0.6" +base64 = "0.7" untrusted = "0.5" chrono = "0.4" diff --git a/README.md b/README.md index c687c12..3c848f1 100644 --- a/README.md +++ b/README.md @@ -76,14 +76,15 @@ those require setting the expected value in the `Validation` struct. Since validating time fields is always a bit tricky due to clock skew, you can add some leeway to the `iat`, `exp` and `nbf` validation by setting a `leeway` parameter. -Last but not least, if you are not using HS256 for the algorithm, you will need to update the `algorithms` field of the `Validation` struct -to the one you are using. +Last but not least, you will need to set the algorithm(s) allowed for this token if you are not using `HS256`. ```rust use jsonwebtoken::{Validation, Algorithm}; -// Default valuation +// Default valuation: the only algo allowed is HS256 let validation = Validation::default(); +// Quick way to setup a validation where only the algorithm changes +let validation = Validation::new(Algorithm::HS512); // Adding some leeway (in seconds) for iat, exp and nbf checks let mut validation = Validation {leeway: 60, ..Default::default()}; // Checking issuer @@ -92,8 +93,6 @@ let mut validation = Validation {iss: Some("issuer".to_string()), ..Default::def let mut validation = Validation::default(); validation.set_audience(&"Me"); // string validation.set_audience(&["Me", "You"]); // array of strings -// Will error if the token given has an algorithm that isn't HS256 -let mut validation = Validation {algorithms: Some(vec![Algorithm::HS256]), ..Default::default()}; ``` ## Algorithms diff --git a/examples/custom_header.rs b/examples/custom_header.rs index d552c50..5fdc078 100644 --- a/examples/custom_header.rs +++ b/examples/custom_header.rs @@ -29,7 +29,7 @@ fn main() { }; println!("{:?}", token); - let token_data = match decode::(&token, key.as_ref(), &Validation::default()) { + let token_data = match decode::(&token, key.as_ref(), &Validation::new(Algorithm::HS512)) { Ok(c) => c, Err(err) => match *err.kind() { ErrorKind::InvalidToken => panic!(), // Example on how to handle a specific error diff --git a/examples/validation.rs b/examples/validation.rs index 8821dde..fcdd841 100644 --- a/examples/validation.rs +++ b/examples/validation.rs @@ -23,7 +23,10 @@ fn main() { Err(_) => panic!() // in practice you would return the error }; - let validation = Validation {sub: Some("b@b.com".to_string()), ..Validation::default()}; + let validation = Validation { + sub: Some("b@b.com".to_string()), + ..Validation::default() + }; let token_data = match decode::(&token, key.as_ref(), &validation) { Ok(c) => c, diff --git a/src/lib.rs b/src/lib.rs index 97647f6..2f1f4ab 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -90,7 +90,7 @@ macro_rules! expect_two { /// ```rust,ignore /// #[macro_use] /// extern crate serde_derive; -/// use jsonwebtoken::{decode, Validation}; +/// use jsonwebtoken::{decode, Validation, Algorithm}; /// /// #[derive(Debug, Serialize, Deserialize)] /// struct Claims { @@ -100,7 +100,7 @@ macro_rules! expect_two { /// /// let token = "a.jwt.token".to_string(); /// // Claims is a struct that implements Deserialize -/// let token_data = decode::(&token, "secret", &Validation::default()); +/// let token_data = decode::(&token, "secret", &Validation::new(Algorithm::HS256)); /// ``` pub fn decode(token: &str, key: &[u8], validation: &Validation) -> Result> { let (signature, signing_input) = expect_two!(token.rsplitn(2, '.')); @@ -111,10 +111,8 @@ pub fn decode(token: &str, key: &[u8], validation: &Validat return Err(ErrorKind::InvalidSignature.into()); } - if let Some(ref allowed_algs) = validation.algorithms { - if !allowed_algs.contains(&header.alg) { - return Err(ErrorKind::InvalidAlgorithm.into()); - } + if !validation.algorithms.contains(&header.alg) { + return Err(ErrorKind::InvalidAlgorithm.into()); } let (decoded_claims, claims_map): (T, _) = from_jwt_part_claims(claims)?; diff --git a/src/validation.rs b/src/validation.rs index e1465ad..7025b91 100644 --- a/src/validation.rs +++ b/src/validation.rs @@ -67,14 +67,21 @@ pub struct Validation { /// /// Defaults to `None`. pub sub: Option, - /// If it contains a value, the validation will check that the `alg` of the header is container + /// If it contains a value, the validation will check that the `alg` of the header is contained /// in the ones provided and will error otherwise. /// - /// Defaults to `None`. - pub algorithms: Option>, + /// Defaults to `vec![Algorithm::HS256]`. + pub algorithms: Vec, } impl Validation { + /// Create a default validation setup allowing the given alg + pub fn new(alg: Algorithm) -> Validation { + let mut validation = Validation::default(); + validation.algorithms = vec![alg]; + validation + } + /// Since `aud` can be either a String or an array of String in the JWT spec, this method will take /// care of serializing the value. pub fn set_audience(&mut self, audience: &T) { @@ -95,7 +102,7 @@ impl Default for Validation { sub: None, aud: None, - algorithms: None, + algorithms: vec![Algorithm::HS256], } } } diff --git a/tests/lib.rs b/tests/lib.rs index 185cd6b..82217d7 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -78,7 +78,7 @@ fn decode_token_invalid_signature() { #[should_panic(expected = "InvalidAlgorithm")] fn decode_token_wrong_algorithm() { let token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJiQGIuY29tIiwiY29tcGFueSI6IkFDTUUifQ.I1BvFoHe94AFf09O6tDbcSB8-jp8w6xZqmyHIwPeSdY"; - let claims = decode::(token, "secret".as_ref(), &Validation {algorithms: Some(vec![Algorithm::RS512]), ..Validation::default()}); + let claims = decode::(token, "secret".as_ref(), &Validation::new(Algorithm::RS512)); claims.unwrap(); } diff --git a/tests/rsa.rs b/tests/rsa.rs index da6b172..423a5a8 100644 --- a/tests/rsa.rs +++ b/tests/rsa.rs @@ -26,7 +26,7 @@ fn round_trip_claim() { company: "ACME".to_string() }; let token = encode(&Header::new(Algorithm::RS256), &my_claims, include_bytes!("private_rsa_key.der")).unwrap(); - let token_data = decode::(&token, include_bytes!("public_rsa_key.der"), &Validation::default()).unwrap(); + let token_data = decode::(&token, include_bytes!("public_rsa_key.der"), &Validation::new(Algorithm::RS256)).unwrap(); assert_eq!(my_claims, token_data.claims); assert!(token_data.header.kid.is_none()); }