diff --git a/CHANGELOG.md b/CHANGELOG.md index fce575c..ab1d147 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ - Remove deprecated `dangerous_unsafe_decode` - `Validation::iss` is now a `HashSet` instead of a single value - `decode` will now error if `Validation::algorithms` is empty +- Add JWKs types for easy interop with various Oauth providers ## 7.2.0 (2020-06-30) diff --git a/examples/custom_chrono.rs b/examples/custom_chrono.rs index a5950d4..987b859 100644 --- a/examples/custom_chrono.rs +++ b/examples/custom_chrono.rs @@ -1,5 +1,5 @@ use chrono::prelude::*; -use jsonwebtoken::{DecodingKey, EncodingKey, Header, Validation}; +use jsonwebtoken::{Algorithm, DecodingKey, EncodingKey, Header, Validation}; use serde::{Deserialize, Serialize}; const SECRET: &str = "some-secret"; @@ -56,7 +56,9 @@ mod jwt_numeric_date { use super::super::{Claims, SECRET}; use chrono::{Duration, TimeZone, Utc}; - use jsonwebtoken::{decode, encode, DecodingKey, EncodingKey, Header, Validation}; + use jsonwebtoken::{ + decode, encode, Algorithm, DecodingKey, EncodingKey, Header, Validation, + }; #[test] fn round_trip() { @@ -75,7 +77,7 @@ mod jwt_numeric_date { let decoded = decode::( &token, &DecodingKey::from_secret(SECRET.as_ref()), - &Validation::default(), + &Validation::new(Algorithm::HS256), ) .expect("Failed to decode token"); @@ -90,7 +92,7 @@ mod jwt_numeric_date { let decode_result = decode::( &overflow_token, &DecodingKey::from_secret(SECRET.as_ref()), - &Validation::default(), + &Validation::new(Algorithm::HS256), ); assert!(decode_result.is_err()); @@ -111,7 +113,7 @@ mod jwt_numeric_date { let decoded = decode::( &token, &DecodingKey::from_secret(SECRET.as_ref()), - &Validation::default(), + &Validation::new(Algorithm::HS256), ) .expect("Failed to decode token") .claims; @@ -139,7 +141,7 @@ fn main() -> Result<(), Box> { let token_data = jsonwebtoken::decode::( &token, &DecodingKey::from_secret(SECRET.as_ref()), - &Validation::default(), + &Validation::new(Algorithm::HS256), )?; println!("token data:\n{:#?}", &token_data); diff --git a/examples/validation.rs b/examples/validation.rs index 928770c..0edc3c2 100644 --- a/examples/validation.rs +++ b/examples/validation.rs @@ -1,5 +1,5 @@ use jsonwebtoken::errors::ErrorKind; -use jsonwebtoken::{decode, encode, DecodingKey, EncodingKey, Header, Validation}; +use jsonwebtoken::{decode, encode, Algorithm, DecodingKey, EncodingKey, Header, Validation}; use serde::{Deserialize, Serialize}; #[derive(Debug, Serialize, Deserialize)] @@ -18,7 +18,8 @@ fn main() { Err(_) => panic!(), // in practice you would return the error }; - let validation = Validation { sub: Some("b@b.com".to_string()), ..Validation::default() }; + let mut validation = Validation::new(Algorithm::HS256); + validation.sub = Some("b@b.com".to_string()); let token_data = match decode::(&token, &DecodingKey::from_secret(key), &validation) { Ok(c) => c, Err(err) => match *err.kind() { diff --git a/src/decoding.rs b/src/decoding.rs index cb6b8be..90645b3 100644 --- a/src/decoding.rs +++ b/src/decoding.rs @@ -140,26 +140,20 @@ impl DecodingKey { /// Verify signature of a JWT, and return header object and raw payload /// /// If the token or its signature is invalid, it will return an error. -/// -/// ```rust/// -/// use jsonwebtoken::{verify_signature, DecodingKey, Validation, Algorithm}; -/// -/// -/// let token = "a.jwt.token".to_string(); -/// let token_message = verify_signature(&token, &DecodingKey::from_secret("secret".as_ref()), &Validation::new(Algorithm::HS256)); -/// ``` -pub fn verify_signature<'a>( +fn verify_signature<'a>( token: &'a str, key: &DecodingKey, validation: &Validation, ) -> Result<(Header, &'a str)> { - if validation.algorithms.is_empty() { + if validation.validate_signature && validation.algorithms.is_empty() { return Err(new_error(ErrorKind::MissingAlgorithm)); } - for alg in &validation.algorithms { - if key.family != alg.family() { - return Err(new_error(ErrorKind::InvalidAlgorithm)); + if validation.validate_signature { + for alg in &validation.algorithms { + if key.family != alg.family() { + return Err(new_error(ErrorKind::InvalidAlgorithm)); + } } } @@ -167,11 +161,11 @@ pub fn verify_signature<'a>( let (payload, header) = expect_two!(message.rsplitn(2, '.')); let header = Header::from_encoded(header)?; - if !validation.algorithms.contains(&header.alg) { + if validation.validate_signature && !validation.algorithms.contains(&header.alg) { return Err(new_error(ErrorKind::InvalidAlgorithm)); } - if !verify(signature, message.as_bytes(), key, header.alg)? { + if validation.validate_signature && !verify(signature, message.as_bytes(), key, header.alg)? { return Err(new_error(ErrorKind::InvalidSignature)); } @@ -212,72 +206,6 @@ pub fn decode( } } -/// Decode a JWT without any signature verification/validations. -/// -/// NOTE: Do not use this unless you know what you are doing! If the token's signature is invalid, it will *not* return an error. -/// -/// ```rust -/// use serde::{Deserialize, Serialize}; -/// use jsonwebtoken::{dangerous_insecure_decode, Validation, Algorithm}; -/// -/// #[derive(Debug, Serialize, Deserialize)] -/// struct Claims { -/// sub: String, -/// company: String -/// } -/// -/// let token = "a.jwt.token".to_string(); -/// // Claims is a struct that implements Deserialize -/// let token_message = dangerous_insecure_decode::(&token); -/// ``` -pub fn dangerous_insecure_decode(token: &str) -> Result> { - let (_, message) = expect_two!(token.rsplitn(2, '.')); - let (claims, header) = expect_two!(message.rsplitn(2, '.')); - let header = Header::from_encoded(header)?; - - let (decoded_claims, _): (T, _) = from_jwt_part_claims(claims)?; - - Ok(TokenData { header, claims: decoded_claims }) -} - -/// Decode and validate a JWT without any signature verification. -/// -/// If the token is invalid or the claims fail validation, it will return an error. -/// -/// NOTE: Do not use this unless you know what you are doing! If the token's signature is invalid, it will *not* return an error. -/// -/// ```rust -/// use serde::{Deserialize, Serialize}; -/// use jsonwebtoken::{dangerous_insecure_decode_with_validation, Validation, Algorithm}; -/// -/// #[derive(Debug, Serialize, Deserialize)] -/// struct Claims { -/// sub: String, -/// company: String -/// } -/// -/// let token = "a.jwt.token"; -/// // Claims is a struct that implements Deserialize -/// let token_message = dangerous_insecure_decode_with_validation::(&token, &Validation::new(Algorithm::HS256)); -/// ``` -pub fn dangerous_insecure_decode_with_validation( - token: &str, - validation: &Validation, -) -> Result> { - let (_, message) = expect_two!(token.rsplitn(2, '.')); - let (claims, header) = expect_two!(message.rsplitn(2, '.')); - let header = Header::from_encoded(header)?; - - if !validation.algorithms.contains(&header.alg) { - return Err(new_error(ErrorKind::InvalidAlgorithm)); - } - - let (decoded_claims, claims_map): (T, _) = from_jwt_part_claims(claims)?; - validate(&claims_map, validation)?; - - Ok(TokenData { header, claims: decoded_claims }) -} - /// Decode a JWT without any signature verification/validations and return its [Header](struct.Header.html). /// /// If the token has an invalid format (ie 3 parts separated by a `.`), it will return an error. diff --git a/src/lib.rs b/src/lib.rs index 78ca270..7e2c7a8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -17,10 +17,7 @@ mod serialization; mod validation; pub use algorithms::Algorithm; -pub use decoding::{ - dangerous_insecure_decode, dangerous_insecure_decode_with_validation, decode, decode_header, - verify_signature, DecodingKey, TokenData, -}; +pub use decoding::{decode, decode_header, DecodingKey, TokenData}; pub use encoding::{encode, EncodingKey}; pub use header::Header; pub use validation::{get_current_timestamp, Validation}; diff --git a/src/validation.rs b/src/validation.rs index fce46f7..aa8d3c3 100644 --- a/src/validation.rs +++ b/src/validation.rs @@ -12,18 +12,16 @@ use crate::errors::{new_error, ErrorKind, Result}; /// All time validation happen on UTC timestamps as seconds. /// /// ```rust -/// use jsonwebtoken::Validation; -/// -/// // Default value -/// let validation = Validation::default(); -/// -/// // Changing one parameter -/// let mut validation = Validation {leeway: 60, ..Default::default()}; +/// use jsonwebtoken::{Validation, Algorithm}; /// +/// let mut validation = Validation::new(Algorithm::HS256); +/// validation.leeway = 5; /// // Setting audience -/// let mut validation = Validation::default(); /// validation.set_audience(&["Me"]); // a single string /// validation.set_audience(&["Me", "You"]); // array of strings +/// // or issuer +/// validation.set_iss(&["Me"]); // a single string +/// validation.set_iss(&["Me", "You"]); // array of strings /// ``` #[derive(Debug, Clone, PartialEq)] pub struct Validation { @@ -64,12 +62,27 @@ pub struct Validation { /// /// Defaults to `vec![Algorithm::HS256]`. pub algorithms: Vec, + + /// Whether to validate the JWT signature. Very insecure to turn that off + pub(crate) validate_signature: bool, } impl Validation { /// Create a default validation setup allowing the given alg pub fn new(alg: Algorithm) -> Validation { - Validation { algorithms: vec![alg], ..Default::default() } + Validation { + algorithms: vec![alg], + leeway: 0, + + validate_exp: true, + validate_nbf: false, + + iss: None, + sub: None, + aud: None, + + validate_signature: true, + } } /// `aud` is a collection of one or more acceptable audience members @@ -81,22 +94,12 @@ impl Validation { pub fn set_iss(&mut self, items: &[T]) { self.iss = Some(items.iter().map(|x| x.to_string()).collect()) } -} -impl Default for Validation { - fn default() -> Validation { - Validation { - leeway: 0, - - validate_exp: true, - validate_nbf: false, - - iss: None, - sub: None, - aud: None, - - algorithms: vec![Algorithm::HS256], - } + /// Whether to validate the JWT cryptographic signature + /// Very insecure to turn that off, only do it if you know what you're doing. + /// With this flag turned off, you should not trust any of the values of the claims. + pub fn insecure_disable_signature_validation(&mut self) { + self.validate_signature = false; } } @@ -190,12 +193,13 @@ mod tests { use super::{get_current_timestamp, validate, Validation}; use crate::errors::ErrorKind; + use crate::Algorithm; #[test] fn exp_in_future_ok() { let mut claims = Map::new(); claims.insert("exp".to_string(), to_value(get_current_timestamp() + 10000).unwrap()); - let res = validate(&claims, &Validation::default()); + let res = validate(&claims, &Validation::new(Algorithm::HS256)); assert!(res.is_ok()); } @@ -203,7 +207,7 @@ mod tests { fn exp_in_past_fails() { let mut claims = Map::new(); claims.insert("exp".to_string(), to_value(get_current_timestamp() - 100000).unwrap()); - let res = validate(&claims, &Validation::default()); + let res = validate(&claims, &Validation::new(Algorithm::HS256)); assert!(res.is_err()); match res.unwrap_err().kind() { @@ -216,7 +220,8 @@ mod tests { fn exp_in_past_but_in_leeway_ok() { let mut claims = Map::new(); claims.insert("exp".to_string(), to_value(get_current_timestamp() - 500).unwrap()); - let validation = Validation { leeway: 1000 * 60, ..Default::default() }; + let mut validation = Validation::new(Algorithm::HS256); + validation.leeway = 1000 * 60; let res = validate(&claims, &validation); assert!(res.is_ok()); } @@ -225,7 +230,7 @@ mod tests { #[test] fn validation_called_even_if_field_is_empty() { let claims = Map::new(); - let res = validate(&claims, &Validation::default()); + let res = validate(&claims, &Validation::new(Algorithm::HS256)); assert!(res.is_err()); match res.unwrap_err().kind() { ErrorKind::ExpiredSignature => (), @@ -237,8 +242,9 @@ mod tests { fn nbf_in_past_ok() { let mut claims = Map::new(); claims.insert("nbf".to_string(), to_value(get_current_timestamp() - 10000).unwrap()); - let validation = - Validation { validate_exp: false, validate_nbf: true, ..Validation::default() }; + let mut validation = Validation::new(Algorithm::HS256); + validation.validate_exp = false; + validation.validate_nbf = true; let res = validate(&claims, &validation); assert!(res.is_ok()); } @@ -247,8 +253,9 @@ mod tests { fn nbf_in_future_fails() { let mut claims = Map::new(); claims.insert("nbf".to_string(), to_value(get_current_timestamp() + 100000).unwrap()); - let validation = - Validation { validate_exp: false, validate_nbf: true, ..Validation::default() }; + let mut validation = Validation::new(Algorithm::HS256); + validation.validate_exp = false; + validation.validate_nbf = true; let res = validate(&claims, &validation); assert!(res.is_err()); @@ -262,12 +269,10 @@ mod tests { fn nbf_in_future_but_in_leeway_ok() { let mut claims = Map::new(); claims.insert("nbf".to_string(), to_value(get_current_timestamp() + 500).unwrap()); - let validation = Validation { - leeway: 1000 * 60, - validate_nbf: true, - validate_exp: false, - ..Default::default() - }; + let mut validation = Validation::new(Algorithm::HS256); + validation.validate_exp = false; + validation.validate_nbf = true; + validation.leeway = 1000 * 60; let res = validate(&claims, &validation); assert!(res.is_ok()); } @@ -277,10 +282,9 @@ mod tests { let mut claims = Map::new(); claims.insert("iss".to_string(), to_value("Keats").unwrap()); - let mut iss = std::collections::HashSet::new(); - iss.insert("Keats".to_string()); - - let validation = Validation { validate_exp: false, iss: Some(iss), ..Default::default() }; + let mut validation = Validation::new(Algorithm::HS256); + validation.validate_exp = false; + validation.set_iss(&["Keats"]); let res = validate(&claims, &validation); assert!(res.is_ok()); } @@ -290,10 +294,9 @@ mod tests { let mut claims = Map::new(); claims.insert("iss".to_string(), to_value("Hacked").unwrap()); - let mut iss = std::collections::HashSet::new(); - iss.insert("Keats".to_string()); - - let validation = Validation { validate_exp: false, iss: Some(iss), ..Default::default() }; + let mut validation = Validation::new(Algorithm::HS256); + validation.validate_exp = false; + validation.set_iss(&["Keats"]); let res = validate(&claims, &validation); assert!(res.is_err()); @@ -307,10 +310,9 @@ mod tests { fn iss_missing_fails() { let claims = Map::new(); - let mut iss = std::collections::HashSet::new(); - iss.insert("Keats".to_string()); - - let validation = Validation { validate_exp: false, iss: Some(iss), ..Default::default() }; + let mut validation = Validation::new(Algorithm::HS256); + validation.validate_exp = false; + validation.set_iss(&["Keats"]); let res = validate(&claims, &validation); assert!(res.is_err()); @@ -324,11 +326,10 @@ mod tests { fn sub_ok() { let mut claims = Map::new(); claims.insert("sub".to_string(), to_value("Keats").unwrap()); - let validation = Validation { - validate_exp: false, - sub: Some("Keats".to_string()), - ..Default::default() - }; + let mut validation = Validation::new(Algorithm::HS256); + validation.validate_exp = false; + validation.sub = Some("Keats".to_owned()); + let res = validate(&claims, &validation); assert!(res.is_ok()); } @@ -337,11 +338,10 @@ mod tests { fn sub_not_matching_fails() { let mut claims = Map::new(); claims.insert("sub".to_string(), to_value("Hacked").unwrap()); - let validation = Validation { - validate_exp: false, - sub: Some("Keats".to_string()), - ..Default::default() - }; + let mut validation = Validation::new(Algorithm::HS256); + validation.validate_exp = false; + validation.sub = Some("Keats".to_owned()); + let res = validate(&claims, &validation); assert!(res.is_err()); @@ -354,11 +354,10 @@ mod tests { #[test] fn sub_missing_fails() { let claims = Map::new(); - let validation = Validation { - validate_exp: false, - sub: Some("Keats".to_string()), - ..Default::default() - }; + let mut validation = Validation::new(Algorithm::HS256); + validation.validate_exp = false; + validation.sub = Some("Keats".to_owned()); + let res = validate(&claims, &validation); assert!(res.is_err()); @@ -372,7 +371,8 @@ mod tests { fn aud_string_ok() { let mut claims = Map::new(); claims.insert("aud".to_string(), to_value(["Everyone"]).unwrap()); - let mut validation = Validation { validate_exp: false, ..Validation::default() }; + let mut validation = Validation::new(Algorithm::HS256); + validation.validate_exp = false; validation.set_audience(&["Everyone"]); let res = validate(&claims, &validation); assert!(res.is_ok()); @@ -382,7 +382,8 @@ mod tests { fn aud_array_of_string_ok() { let mut claims = Map::new(); claims.insert("aud".to_string(), to_value(["UserA", "UserB"]).unwrap()); - let mut validation = Validation { validate_exp: false, ..Validation::default() }; + let mut validation = Validation::new(Algorithm::HS256); + validation.validate_exp = false; validation.set_audience(&["UserA", "UserB"]); let res = validate(&claims, &validation); assert!(res.is_ok()); @@ -392,7 +393,8 @@ mod tests { fn aud_type_mismatch_fails() { let mut claims = Map::new(); claims.insert("aud".to_string(), to_value(["Everyone"]).unwrap()); - let mut validation = Validation { validate_exp: false, ..Validation::default() }; + let mut validation = Validation::new(Algorithm::HS256); + validation.validate_exp = false; validation.set_audience(&["UserA", "UserB"]); let res = validate(&claims, &validation); assert!(res.is_err()); @@ -407,7 +409,8 @@ mod tests { fn aud_correct_type_not_matching_fails() { let mut claims = Map::new(); claims.insert("aud".to_string(), to_value(["Everyone"]).unwrap()); - let mut validation = Validation { validate_exp: false, ..Validation::default() }; + let mut validation = Validation::new(Algorithm::HS256); + validation.validate_exp = false; validation.set_audience(&["None"]); let res = validate(&claims, &validation); assert!(res.is_err()); @@ -421,7 +424,8 @@ mod tests { #[test] fn aud_missing_fails() { let claims = Map::new(); - let mut validation = Validation { validate_exp: false, ..Validation::default() }; + let mut validation = Validation::new(Algorithm::HS256); + validation.validate_exp = false; validation.set_audience(&["None"]); let res = validate(&claims, &validation); assert!(res.is_err()); @@ -434,22 +438,17 @@ mod tests { // https://github.com/Keats/jsonwebtoken/issues/51 #[test] - #[should_panic] fn does_validation_in_right_order() { let mut claims = Map::new(); claims.insert("exp".to_string(), to_value(get_current_timestamp() + 10000).unwrap()); - let mut iss = std::collections::HashSet::new(); - iss.insert("iss no check".to_string()); + let mut validation = Validation::new(Algorithm::HS256); + validation.leeway = 5; + validation.set_iss(&["iss no check"]); + validation.set_audience(&["iss no check"]); + + let res = validate(&claims, &validation); - let v = Validation { - leeway: 5, - validate_exp: true, - iss: Some(iss), - sub: Some("sub no check".to_string()), - ..Validation::default() - }; - let res = validate(&claims, &v); // It errors because it needs to validate iss/sub which are missing assert!(res.is_err()); match res.unwrap_err().kind() { @@ -470,9 +469,10 @@ mod tests { let aud = "my-googleclientid1234.apps.googleusercontent.com".to_string(); let mut aud_hashset = std::collections::HashSet::new(); aud_hashset.insert(aud); + let mut validation = Validation::new(Algorithm::HS256); + validation.validate_exp = false; + validation.set_audience(&["my-googleclientid1234.apps.googleusercontent.com"]); - let validation = - Validation { aud: Some(aud_hashset), validate_exp: false, ..Validation::default() }; let res = validate(&claims, &validation); println!("{:?}", res); assert!(res.is_ok()); diff --git a/tests/hmac.rs b/tests/hmac.rs index d2e1f5e..8968dfa 100644 --- a/tests/hmac.rs +++ b/tests/hmac.rs @@ -1,9 +1,8 @@ use chrono::Utc; -use jsonwebtoken::dangerous_insecure_decode_with_validation; +use jsonwebtoken::errors::ErrorKind; use jsonwebtoken::{ crypto::{sign, verify}, - dangerous_insecure_decode, decode, decode_header, encode, Algorithm, DecodingKey, EncodingKey, - Header, Validation, + decode, decode_header, encode, Algorithm, DecodingKey, EncodingKey, Header, Validation, }; use serde::{Deserialize, Serialize}; @@ -39,9 +38,12 @@ fn encode_with_custom_header() { }; let header = Header { kid: Some("kid".to_string()), ..Default::default() }; let token = encode(&header, &my_claims, &EncodingKey::from_secret(b"secret")).unwrap(); - let token_data = - decode::(&token, &DecodingKey::from_secret(b"secret"), &Validation::default()) - .unwrap(); + let token_data = decode::( + &token, + &DecodingKey::from_secret(b"secret"), + &Validation::new(Algorithm::HS256), + ) + .unwrap(); assert_eq!(my_claims, token_data.claims); assert_eq!("kid", token_data.header.kid.unwrap()); } @@ -55,9 +57,12 @@ fn round_trip_claim() { }; let token = encode(&Header::default(), &my_claims, &EncodingKey::from_secret(b"secret")).unwrap(); - let token_data = - decode::(&token, &DecodingKey::from_secret(b"secret"), &Validation::default()) - .unwrap(); + let token_data = decode::( + &token, + &DecodingKey::from_secret(b"secret"), + &Validation::new(Algorithm::HS256), + ) + .unwrap(); assert_eq!(my_claims, token_data.claims); assert!(token_data.header.kid.is_none()); } @@ -65,8 +70,11 @@ fn round_trip_claim() { #[test] fn decode_token() { let token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJiQGIuY29tIiwiY29tcGFueSI6IkFDTUUiLCJleHAiOjI1MzI1MjQ4OTF9.9r56oF7ZliOBlOAyiOFperTGxBtPykRQiWNFxhDCW98"; - let claims = - decode::(token, &DecodingKey::from_secret(b"secret"), &Validation::default()); + let claims = decode::( + token, + &DecodingKey::from_secret(b"secret"), + &Validation::new(Algorithm::HS256), + ); println!("{:?}", claims); claims.unwrap(); } @@ -75,8 +83,11 @@ fn decode_token() { #[should_panic(expected = "InvalidToken")] fn decode_token_missing_parts() { let token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9"; - let claims = - decode::(token, &DecodingKey::from_secret(b"secret"), &Validation::default()); + let claims = decode::( + token, + &DecodingKey::from_secret(b"secret"), + &Validation::new(Algorithm::HS256), + ); claims.unwrap(); } @@ -85,8 +96,11 @@ fn decode_token_missing_parts() { fn decode_token_invalid_signature() { let token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJiQGIuY29tIiwiY29tcGFueSI6IkFDTUUifQ.wrong"; - let claims = - decode::(token, &DecodingKey::from_secret(b"secret"), &Validation::default()); + let claims = decode::( + token, + &DecodingKey::from_secret(b"secret"), + &Validation::new(Algorithm::HS256), + ); claims.unwrap(); } @@ -117,8 +131,11 @@ fn encode_wrong_alg_family() { #[test] fn decode_token_with_bytes_secret() { let token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJiQGIuY29tIiwiY29tcGFueSI6IkFDTUUiLCJleHAiOjI1MzI1MjQ4OTF9.Hm0yvKH25TavFPz7J_coST9lZFYH1hQo0tvhvImmaks"; - let claims = - decode::(token, &DecodingKey::from_secret(b"\x01\x02\x03"), &Validation::default()); + let claims = decode::( + token, + &DecodingKey::from_secret(b"\x01\x02\x03"), + &Validation::new(Algorithm::HS256), + ); assert!(claims.is_ok()); } @@ -131,60 +148,38 @@ fn decode_header_only() { } #[test] -fn dangerous_insecure_decode_token() { +fn dangerous_insecure_decode_valid_token() { let token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJiQGIuY29tIiwiY29tcGFueSI6IkFDTUUiLCJleHAiOjI1MzI1MjQ4OTF9.9r56oF7ZliOBlOAyiOFperTGxBtPykRQiWNFxhDCW98"; - let claims = dangerous_insecure_decode::(token); - claims.unwrap(); -} - -#[test] -#[should_panic(expected = "InvalidToken")] -fn dangerous_insecure_decode_token_missing_parts() { - let token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9"; - let claims = dangerous_insecure_decode::(token); + let mut validation = Validation::new(Algorithm::HS256); + validation.insecure_disable_signature_validation(); + let claims = decode::(token, &DecodingKey::from_secret(&[]), &validation); claims.unwrap(); } #[test] fn dangerous_insecure_decode_token_invalid_signature() { let token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJiQGIuY29tIiwiY29tcGFueSI6IkFDTUUiLCJleHAiOjI1MzI1MjQ4OTF9.wrong"; - let claims = dangerous_insecure_decode::(token); + let mut validation = Validation::new(Algorithm::HS256); + validation.insecure_disable_signature_validation(); + let claims = decode::(token, &DecodingKey::from_secret(&[]), &validation); claims.unwrap(); } #[test] fn dangerous_insecure_decode_token_wrong_algorithm() { let token = "eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJiQGIuY29tIiwiY29tcGFueSI6IkFDTUUiLCJleHAiOjI1MzI1MjQ4OTF9.fLxey-hxAKX5rNHHIx1_Ch0KmrbiuoakDVbsJjLWrx8fbjKjrPuWMYEJzTU3SBnYgnZokC-wqSdqckXUOunC-g"; - let claims = dangerous_insecure_decode::(token); + let mut validation = Validation::new(Algorithm::HS256); + validation.insecure_disable_signature_validation(); + let claims = decode::(token, &DecodingKey::from_secret(&[]), &validation); claims.unwrap(); } #[test] -fn dangerous_insecure_decode_token_with_validation() { - let token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJiQGIuY29tIiwiY29tcGFueSI6IkFDTUUiLCJleHAiOjI1MzI1MjQ4OTF9.9r56oF7ZliOBlOAyiOFperTGxBtPykRQiWNFxhDCW98"; - let claims = dangerous_insecure_decode_with_validation::(token, &Validation::default()); - claims.unwrap(); -} - -#[test] -#[should_panic(expected = "InvalidToken")] -fn dangerous_insecure_decode_token_with_validation_missing_parts() { - let token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9"; - let claims = dangerous_insecure_decode_with_validation::(token, &Validation::default()); - claims.unwrap(); -} - -#[test] -fn dangerous_insecure_decode_token_with_validation_invalid_signature() { - let token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJiQGIuY29tIiwiY29tcGFueSI6IkFDTUUiLCJleHAiOjI1MzI1MjQ4OTF9.wrong"; - let claims = dangerous_insecure_decode_with_validation::(token, &Validation::default()); - claims.unwrap(); -} - -#[test] -#[should_panic(expected = "InvalidAlgorithm")] fn dangerous_insecure_decode_token_with_validation_wrong_algorithm() { - let token = "eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJiQGIuY29tIiwiY29tcGFueSI6IkFDTUUiLCJleHAiOjI1MzI1MjQ4OTF9.fLxey-hxAKX5rNHHIx1_Ch0KmrbiuoakDVbsJjLWrx8fbjKjrPuWMYEJzTU3SBnYgnZokC-wqSdqckXUOunC-g"; - let claims = dangerous_insecure_decode_with_validation::(token, &Validation::default()); - claims.unwrap(); + let token = "eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJiQGIuY29tIiwiY29tcGFueSI6IkFDTUUiLCJleHAiOjk1MzI1MjQ4OX0.ONtEUTtP1QmyksYH9ijtPCaXoHjZVHcHKZGX1DuJyPiSyKlT93Y-oKgrp_OSkHSu4huxCcVObLzwsdwF-xwiAQ"; + let mut validation = Validation::new(Algorithm::HS256); + validation.insecure_disable_signature_validation(); + let claims = decode::(token, &DecodingKey::from_secret(&[]), &validation); + let err = claims.unwrap_err(); + assert_eq!(err.kind(), &ErrorKind::ExpiredSignature); }