From 4761045934e43c82469e70bb7f64a351d88519b1 Mon Sep 17 00:00:00 2001 From: codedust Date: Sun, 11 Jul 2021 02:32:07 +0200 Subject: [PATCH 1/3] feat: Improved error messages/warnings New: If no secret/publicKey is provided by the user, no signature check is performed. Rather then silently skipping the signature check, this commit introduces a warning in this case. New: If the `exp` claim is not set and the token validation check is skipped, a warning is shown. New: After a successful signature validation a success message is shown. Changed: The `InvalidAlgorithm` error message now shows the selected algorithm and the algorithm specified in the JWT header. New: If no signature validation is performed, the return code is now `2`. All tests have been updated accordingly. --- src/main.rs | 45 ++++++++++++++++++++---------- tests/jwt-cli.rs | 71 +++++++++++++++++++++++++----------------------- 2 files changed, 67 insertions(+), 49 deletions(-) diff --git a/src/main.rs b/src/main.rs index 5bb6f44..565753e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -486,7 +486,7 @@ fn encode_token(matches: &ArgMatches) -> JWTResult { fn decode_token( matches: &ArgMatches, ) -> ( - JWTResult>, + Option>>, JWTResult>, OutputFormat, ) { @@ -533,8 +533,12 @@ fn decode_token( ( match secret { - Some(secret_key) => decode::(&jwt, &secret_key.unwrap(), &secret_validator), - None => dangerous_insecure_decode::(&jwt), + Some(secret_key) => Some(decode::( + &jwt, + &secret_key.unwrap(), + &secret_validator, + )), + None => None, // unable to safely decode token => validated_token is set to None }, token_data, if matches.is_present("json") { @@ -564,12 +568,13 @@ fn print_encoded_token(token: JWTResult) { } fn print_decoded_token( - validated_token: JWTResult>, + validated_token: Option>>, token_data: JWTResult>, + options_algorithm: Algorithm, format: OutputFormat, ) { - if let Err(err) = &validated_token { - match err.kind() { + match validated_token { + Some(Err(ref err)) => match err.kind() { ErrorKind::InvalidToken => { bunt::println!("{$red+bold}The JWT provided is invalid{/$}") } @@ -597,15 +602,20 @@ fn print_decoded_token( ErrorKind::ImmatureSignature => bunt::eprintln!( "{$red+bold}The `nbf` claim is in the future which isn't allowed{/$}" ), - ErrorKind::InvalidAlgorithm => bunt::eprintln!( - "{$red+bold}The JWT provided has a different signing algorithm than the one you \ - provided{/$}", - ), + ErrorKind::InvalidAlgorithm => { + let jwt_algorithm = match token_data { + Ok(ref token) => token.header.alg, + Err(_) => panic!("Error: Invalid token data."), + }; + bunt::eprintln!("{$red+bold}Error: Invalid Signature! The JWT provided has a different signing algorithm ({:?}) than the one selected for validation ({:?}){/$}",jwt_algorithm, options_algorithm) + } _ => bunt::eprintln!( - "{$red+bold}The JWT provided is invalid because{/$} {:?}", + "{$red+bold}The JWT provided is invalid because {:?}{/$}", err ), - }; + }, + Some(Ok(_)) => bunt::eprintln!("{$green+bold}Success! JWT signature is valid!{/$}"), + None => bunt::eprintln!("{$red+bold}Warning! JWT signature has not been validated!{/$}"), } match (format, token_data) { @@ -622,8 +632,9 @@ fn print_decoded_token( } exit(match validated_token { - Err(_) => 1, - Ok(_) => 0, + Some(Ok(_)) => 0, // successful signature check + Some(Err(_)) => 1, // token validation error + None => 2, // no signature check performed }) } @@ -641,7 +652,11 @@ fn main() { ("decode", Some(decode_matches)) => { let (validated_token, token_data, format) = decode_token(decode_matches); - print_decoded_token(validated_token, token_data, format); + let options_algorithm = translate_algorithm(SupportedAlgorithms::from_string( + decode_matches.value_of("algorithm").unwrap(), + )); + + print_decoded_token(validated_token, token_data, options_algorithm, format); } _ => (), } diff --git a/tests/jwt-cli.rs b/tests/jwt-cli.rs index 0f1df2d..3fd6e0d 100644 --- a/tests/jwt-cli.rs +++ b/tests/jwt-cli.rs @@ -253,9 +253,9 @@ mod tests { let decode_matches = decode_matcher.subcommand_matches("decode").unwrap(); let (decoded_token, _, _) = decode_token(&decode_matches); - assert!(decoded_token.is_ok()); + assert!(decoded_token.as_ref().unwrap().is_ok()); - let TokenData { claims, header } = decoded_token.unwrap(); + let TokenData { claims, header } = decoded_token.unwrap().unwrap(); assert_eq!(header.alg, Algorithm::HS256); assert_eq!(header.kid, Some("1234".to_string())); @@ -287,9 +287,9 @@ mod tests { let decode_matches = decode_matcher.subcommand_matches("decode").unwrap(); let (decoded_token, _, _) = decode_token(&decode_matches); - assert!(decoded_token.is_ok()); + assert!(decoded_token.as_ref().unwrap().is_ok()); - let TokenData { claims, header: _ } = decoded_token.unwrap(); + let TokenData { claims, header: _ } = decoded_token.unwrap().unwrap(); let iat = from_value::(claims.0["iat"].clone()); assert!(iat.is_ok()); @@ -309,7 +309,7 @@ mod tests { let decode_matches = decode_matcher.subcommand_matches("decode").unwrap(); let (decoded_token, token_data, _) = decode_token(&decode_matches); - assert!(decoded_token.is_err()); + assert!(decoded_token.as_ref().unwrap().is_err()); let TokenData { claims, header: _ } = token_data.unwrap(); @@ -329,9 +329,9 @@ mod tests { let decode_matches = decode_matcher.subcommand_matches("decode").unwrap(); let (decoded_token, _, _) = decode_token(&decode_matches); - assert!(decoded_token.is_ok()); + assert!(decoded_token.as_ref().unwrap().is_ok()); - let TokenData { claims, header: _ } = decoded_token.unwrap(); + let TokenData { claims, header: _ } = decoded_token.unwrap().unwrap(); let exp = from_value::(claims.0["exp"].clone()); assert!(exp.is_ok()); @@ -358,9 +358,9 @@ mod tests { let decode_matches = decode_matcher.subcommand_matches("decode").unwrap(); let (decoded_token, _, _) = decode_token(&decode_matches); - assert!(decoded_token.is_ok()); + assert!(decoded_token.as_ref().unwrap().is_ok()); - let TokenData { claims, header: _ } = decoded_token.unwrap(); + let TokenData { claims, header: _ } = decoded_token.unwrap().unwrap(); assert!(claims.0.get("iat").is_none()); } @@ -386,9 +386,9 @@ mod tests { let decode_matches = decode_matcher.subcommand_matches("decode").unwrap(); let (decoded_token, _, _) = decode_token(&decode_matches); - assert!(decoded_token.is_ok()); + assert!(decoded_token.as_ref().unwrap().is_ok()); - let TokenData { claims, header: _ } = decoded_token.unwrap(); + let TokenData { claims, header: _ } = decoded_token.unwrap().unwrap(); let exp_claim = from_value::(claims.0["exp"].clone()); assert!(exp_claim.is_ok()); @@ -408,7 +408,7 @@ mod tests { let decode_matches = decode_matcher.subcommand_matches("decode").unwrap(); let (decoded_token, _, _) = decode_token(&decode_matches); - assert!(decoded_token.is_err()); + assert!(decoded_token.as_ref().unwrap().is_err()); } #[test] @@ -431,7 +431,7 @@ mod tests { let decode_matches = decode_matcher.subcommand_matches("decode").unwrap(); let (decoded_token, _, _) = decode_token(&decode_matches); - assert!(decoded_token.is_ok()); + assert!(decoded_token.as_ref().unwrap().is_ok()); } #[test] @@ -454,9 +454,9 @@ mod tests { let decode_matches = decode_matcher.subcommand_matches("decode").unwrap(); let (decoded_token, _, _) = decode_token(&decode_matches); - assert!(decoded_token.is_ok()); + assert!(decoded_token.as_ref().unwrap().is_ok()); - let TokenData { claims, header: _ } = decoded_token.unwrap(); + let TokenData { claims, header: _ } = decoded_token.unwrap().unwrap(); let exp_claim = from_value::(claims.0["exp"].clone()); let iat_claim = from_value::(claims.0["iat"].clone()); @@ -490,9 +490,9 @@ mod tests { let decode_matches = decode_matcher.subcommand_matches("decode").unwrap(); let (decoded_token, _, _) = decode_token(&decode_matches); - assert!(decoded_token.is_ok()); + assert!(decoded_token.as_ref().unwrap().is_ok()); - let TokenData { claims, header: _ } = decoded_token.unwrap(); + let TokenData { claims, header: _ } = decoded_token.unwrap().unwrap(); let nbf_claim = from_value::(claims.0["nbf"].clone()); let iat_claim = from_value::(claims.0["iat"].clone()); @@ -521,7 +521,7 @@ mod tests { let decode_matches = matches.subcommand_matches("decode").unwrap(); let (result, _, _) = decode_token(&decode_matches); - assert!(result.is_ok()); + assert!(result.unwrap().is_ok()); } #[test] @@ -535,9 +535,10 @@ mod tests { ]) .unwrap(); let decode_matches = matches.subcommand_matches("decode").unwrap(); - let (result, _, format) = decode_token(&decode_matches); + let (validated_token, token_data, format) = decode_token(&decode_matches); - assert!(result.is_ok()); + assert!(validated_token.is_none()); // no signature validation + assert!(token_data.is_ok()); assert!(format == OutputFormat::Json); } @@ -557,7 +558,7 @@ mod tests { let decode_matches = matches.subcommand_matches("decode").unwrap(); let (result, _, _) = decode_token(&decode_matches); - assert!(result.is_err()); + assert!(result.unwrap().is_err()); } #[test] @@ -572,9 +573,10 @@ mod tests { ]) .unwrap(); let decode_matches = matches.subcommand_matches("decode").unwrap(); - let (result, _, _) = decode_token(&decode_matches); + let (validated_token, token_data, _) = decode_token(&decode_matches); - assert!(result.is_ok()); + assert!(validated_token.is_none()); // no signature validation + assert!(token_data.is_ok()); } #[test] @@ -587,9 +589,10 @@ mod tests { ]) .unwrap(); let decode_matches = matches.subcommand_matches("decode").unwrap(); - let (result, _, _) = decode_token(&decode_matches); + let (validated_token, token_data, _) = decode_token(&decode_matches); - assert!(result.is_ok()); + assert!(validated_token.is_none()); // no signature validation + assert!(token_data.is_ok()); } #[test] @@ -602,9 +605,10 @@ mod tests { ]) .unwrap(); let decode_matches = matches.subcommand_matches("decode").unwrap(); - let (result, _, _) = decode_token(&decode_matches); + let (validated_token, token_data, _) = decode_token(&decode_matches); - assert!(result.is_ok()); + assert!(validated_token.is_none()); // no signature validation + assert!(token_data.is_ok()); } #[test] @@ -617,9 +621,10 @@ mod tests { ]) .unwrap(); let decode_matches = matches.subcommand_matches("decode").unwrap(); - let (result, _, _) = decode_token(&decode_matches); + let (validated_token, token_data, _) = decode_token(&decode_matches); - assert!(result.is_ok()); + assert!(validated_token.is_none()); // no signature validation + assert!(token_data.is_ok()); } #[test] @@ -653,7 +658,7 @@ mod tests { let decode_matches = decode_matcher.subcommand_matches("decode").unwrap(); let (result, _, _) = decode_token(&decode_matches); - assert!(result.is_ok()); + assert!(result.unwrap().is_ok()); } #[test] @@ -774,9 +779,7 @@ mod tests { let decode_matches = decode_matcher.subcommand_matches("decode").unwrap(); let (result, _, _) = decode_token(&decode_matches); - dbg!(&result); - - assert!(result.is_ok()); + assert!(result.unwrap().is_ok()); } #[test] @@ -810,7 +813,7 @@ mod tests { let decode_matches = decode_matcher.subcommand_matches("decode").unwrap(); let (decoded_token, token_data, _) = decode_token(&decode_matches); - assert!(decoded_token.is_ok()); + assert!(decoded_token.as_ref().unwrap().is_ok()); let TokenData { claims, header: _ } = token_data.unwrap(); From 041f3542a4b3220e591115edb4cf828219d6eec2 Mon Sep 17 00:00:00 2001 From: codedust Date: Wed, 20 Oct 2021 23:01:52 +0200 Subject: [PATCH 2/3] Add verify command This commit introduces a verify command that enforces signature validation. The decode command now does not attempt to validate the token signature and does not expect the parameters `--secret`, `--ignore_exp` and `--alg` any more. This commit also includes some additional code cleanups regarding exit codes. --- src/main.rs | 136 +++++++++++++++++---------- tests/jwt-cli.rs | 236 ++++++++++++++++++++++------------------------- 2 files changed, 196 insertions(+), 176 deletions(-) diff --git a/src/main.rs b/src/main.rs index 565753e..1d63fff 100644 --- a/src/main.rs +++ b/src/main.rs @@ -246,7 +246,26 @@ fn config_options<'a, 'b>() -> App<'a, 'b> { ), ).subcommand( SubCommand::with_name("decode") - .about("Decode a JWT") + .about("Decode a JWT (no signature check is performed)") + .arg( + Arg::with_name("jwt") + .help("the jwt to decode") + .index(1) + .required(true), + ).arg( + Arg::with_name("iso_dates") + .help("display unix timestamps as ISO 8601 dates") + .takes_value(false) + .long("iso8601") + ).arg( + Arg::with_name("json") + .help("render decoded JWT as JSON") + .long("json") + .short("j"), + ), + ).subcommand( + SubCommand::with_name("verify") + .about("Decode a JWT and validate its signature") .arg( Arg::with_name("jwt") .help("the jwt to decode") @@ -271,7 +290,7 @@ fn config_options<'a, 'b>() -> App<'a, 'b> { .takes_value(true) .long("secret") .short("S") - .default_value(""), + .required(true), ).arg( Arg::with_name("json") .help("render decoded JWT as JSON") @@ -483,20 +502,7 @@ fn encode_token(matches: &ArgMatches) -> JWTResult { .and_then(|secret| encode(&header, &claims, &secret)) } -fn decode_token( - matches: &ArgMatches, -) -> ( - Option>>, - JWTResult>, - OutputFormat, -) { - let algorithm = translate_algorithm(SupportedAlgorithms::from_string( - matches.value_of("algorithm").unwrap(), - )); - let secret = match matches.value_of("secret").map(|s| (s, !s.is_empty())) { - Some((secret, true)) => Some(decoding_key_from_secret(&algorithm, secret)), - _ => None, - }; +fn decode_token(matches: &ArgMatches) -> (String, JWTResult>, OutputFormat) { let jwt = matches .value_of("jwt") .map(|value| { @@ -516,13 +522,6 @@ fn decode_token( .trim() .to_owned(); - let secret_validator = Validation { - leeway: 1000, - algorithms: vec![algorithm], - validate_exp: !matches.is_present("ignore_exp"), - ..Default::default() - }; - let token_data = dangerous_insecure_decode::(&jwt).map(|mut token| { if matches.is_present("iso_dates") { token.claims.convert_timestamps(); @@ -532,14 +531,7 @@ fn decode_token( }); ( - match secret { - Some(secret_key) => Some(decode::( - &jwt, - &secret_key.unwrap(), - &secret_validator, - )), - None => None, // unable to safely decode token => validated_token is set to None - }, + jwt, token_data, if matches.is_present("json") { OutputFormat::Json @@ -549,6 +541,24 @@ fn decode_token( ) } +fn verify_token(jwt: &String, matches: &ArgMatches) -> JWTResult> { + let algorithm = translate_algorithm(SupportedAlgorithms::from_string( + matches.value_of("algorithm").unwrap(), + )); + + let secret_validator = Validation { + leeway: 1000, + algorithms: vec![algorithm], + validate_exp: !matches.is_present("ignore_exp"), + ..Default::default() + }; + + let secret = matches.value_of("secret").unwrap(); + let secret_key = decoding_key_from_secret(&algorithm, &secret).unwrap(); + + decode::(jwt, &secret_key, &secret_validator) +} + fn print_encoded_token(token: JWTResult) { match token { Ok(jwt) => { @@ -557,12 +567,10 @@ fn print_encoded_token(token: JWTResult) { } else { print!("{}", jwt); } - exit(0); } Err(err) => { bunt::eprintln!("{$red+bold}Something went awry creating the jwt{/$}\n"); eprintln!("{}", err); - exit(1); } } } @@ -570,13 +578,13 @@ fn print_encoded_token(token: JWTResult) { fn print_decoded_token( validated_token: Option>>, token_data: JWTResult>, - options_algorithm: Algorithm, + options_algorithm: Option, format: OutputFormat, ) { match validated_token { Some(Err(ref err)) => match err.kind() { ErrorKind::InvalidToken => { - bunt::println!("{$red+bold}The JWT provided is invalid{/$}") + bunt::eprintln!("{$red+bold}The JWT provided is invalid{/$}") } ErrorKind::InvalidSignature => { bunt::eprintln!("{$red+bold}The JWT provided has an invalid signature{/$}") @@ -591,7 +599,7 @@ fn print_decoded_token( bunt::eprintln!("{$red+bold}The token has expired (or the `exp` claim is not set). This error can be ignored via the `--ignore-exp` parameter.{/$}") } ErrorKind::InvalidIssuer => { - bunt::println!("{$red+bold}The token issuer is invalid{/$}") + bunt::eprintln!("{$red+bold}The token issuer is invalid{/$}") } ErrorKind::InvalidAudience => { bunt::eprintln!("{$red+bold}The token audience doesn't match the subject{/$}") @@ -607,7 +615,7 @@ fn print_decoded_token( Ok(ref token) => token.header.alg, Err(_) => panic!("Error: Invalid token data."), }; - bunt::eprintln!("{$red+bold}Error: Invalid Signature! The JWT provided has a different signing algorithm ({:?}) than the one selected for validation ({:?}){/$}",jwt_algorithm, options_algorithm) + bunt::eprintln!("{$red+bold}Error: Invalid Signature! The JWT provided has a different signing algorithm ({:?}) than the one selected for validation ({:?}){/$}",jwt_algorithm, options_algorithm.unwrap()) } _ => bunt::eprintln!( "{$red+bold}The JWT provided is invalid because {:?}{/$}", @@ -615,7 +623,19 @@ fn print_decoded_token( ), }, Some(Ok(_)) => bunt::eprintln!("{$green+bold}Success! JWT signature is valid!{/$}"), - None => bunt::eprintln!("{$red+bold}Warning! JWT signature has not been validated!{/$}"), + None => { + // the signature could not be verified + match token_data { + Err(ref err) => match err.kind() { + ErrorKind::InvalidToken => bunt::eprintln!("{$red+bold}Error: The token could not be decoded (invalid token structure).{/$}"), + ErrorKind::Base64(_) => bunt::eprintln!("{$red+bold}Error: The token could not be decoded (invalid Base64 encoding).{/$}"), + ErrorKind::Json(_) => bunt::eprintln!("{$red+bold}Error: The token could not be decoded (error while decoding json).{/$}"), + ErrorKind::Utf8(_) => bunt::eprintln!("{$red+bold}Error: The token could not be decoded (error while decoding UTF8 string).{/$}"), + _ => bunt::eprintln!("{$red+bold}Error: Unexpected error while decoding the token!{/$}"), + } + Ok(_) => bunt::eprintln!("{$red+bold}Warning! JWT signature has not been validated!{/$}"), + } + } } match (format, token_data) { @@ -628,14 +648,8 @@ fn print_decoded_token( bunt::println!("{$bold}Token claims\n------------{/$}"); println!("{}", to_string_pretty(&token.claims).unwrap()); } - (_, Err(_)) => exit(1), + (_, Err(_)) => {} } - - exit(match validated_token { - Some(Ok(_)) => 0, // successful signature check - Some(Err(_)) => 1, // token validation error - None => 2, // no signature check performed - }) } fn main() { @@ -646,17 +660,43 @@ fn main() { warn_unsupported(encode_matches); let token = encode_token(encode_matches); + let return_code: i32 = match &token { + Ok(_) => 0, // token encoded sucessfully + Err(_) => 1, // token could not be encoded + }; print_encoded_token(token); + exit(return_code) } ("decode", Some(decode_matches)) => { - let (validated_token, token_data, format) = decode_token(decode_matches); - + let (_, token_data, format) = decode_token(&decode_matches); + let return_code: i32 = match &token_data { + Ok(_) => 0, // token decoded sucessfully + Err(_) => 1, // token could not be decoded + }; + + print_decoded_token(None, token_data, None, format); + exit(return_code) + } + ("verify", Some(decode_matches)) => { + let (jwt, token_data, format) = decode_token(&decode_matches); + let validated_token = verify_token(&jwt, &decode_matches); + let return_code: i32 = match validated_token { + Ok(_) => 0, // successful signature check + Err(_) => 1, // unsuccessful signature check + }; let options_algorithm = translate_algorithm(SupportedAlgorithms::from_string( decode_matches.value_of("algorithm").unwrap(), )); - print_decoded_token(validated_token, token_data, options_algorithm, format); + print_decoded_token( + Some(validated_token), + token_data, + Some(options_algorithm), + format, + ); + + exit(return_code) } _ => (), } diff --git a/tests/jwt-cli.rs b/tests/jwt-cli.rs index 3fd6e0d..9dacc2c 100644 --- a/tests/jwt-cli.rs +++ b/tests/jwt-cli.rs @@ -5,7 +5,7 @@ mod tests { use super::{ config_options, create_header, decode_token, decoding_key_from_secret, encode_token, encoding_key_from_secret, is_payload_item, is_timestamp_or_duration, translate_algorithm, - OutputFormat, Payload, PayloadItem, SupportedAlgorithms, + verify_token, OutputFormat, Payload, PayloadItem, SupportedAlgorithms, }; use base64::decode as base64_decode; use chrono::{Duration, TimeZone, Utc}; @@ -248,14 +248,16 @@ mod tests { let encode_matches = encode_matcher.subcommand_matches("encode").unwrap(); let encoded_token = encode_token(&encode_matches).unwrap(); let decode_matcher = config_options() - .get_matches_from_safe(vec!["jwt", "decode", "-S", "1234567890", &encoded_token]) + .get_matches_from_safe(vec!["jwt", "verify", "-S", "1234567890", &encoded_token]) .unwrap(); - let decode_matches = decode_matcher.subcommand_matches("decode").unwrap(); - let (decoded_token, _, _) = decode_token(&decode_matches); + let decode_matches = decode_matcher.subcommand_matches("verify").unwrap(); + let (jwt, token_data, _) = decode_token(&decode_matches); + let validated_token = verify_token(&jwt, &decode_matches); - assert!(decoded_token.as_ref().unwrap().is_ok()); + assert!(token_data.is_ok()); + assert!(validated_token.as_ref().is_ok()); - let TokenData { claims, header } = decoded_token.unwrap().unwrap(); + let TokenData { claims, header } = validated_token.unwrap(); assert_eq!(header.alg, Algorithm::HS256); assert_eq!(header.kid, Some("1234".to_string())); @@ -282,14 +284,14 @@ mod tests { let encode_matches = encode_matcher.subcommand_matches("encode").unwrap(); let encoded_token = encode_token(&encode_matches).unwrap(); let decode_matcher = config_options() - .get_matches_from_safe(vec!["jwt", "decode", "-S", "1234567890", &encoded_token]) + .get_matches_from_safe(vec!["jwt", "decode", &encoded_token]) .unwrap(); let decode_matches = decode_matcher.subcommand_matches("decode").unwrap(); - let (decoded_token, _, _) = decode_token(&decode_matches); + let (_, decoded_token, _) = decode_token(&decode_matches); - assert!(decoded_token.as_ref().unwrap().is_ok()); + assert!(decoded_token.is_ok()); - let TokenData { claims, header: _ } = decoded_token.unwrap().unwrap(); + let TokenData { claims, header: _ } = decoded_token.unwrap(); let iat = from_value::(claims.0["iat"].clone()); assert!(iat.is_ok()); @@ -304,14 +306,14 @@ mod tests { let encode_matches = encode_matcher.subcommand_matches("encode").unwrap(); let encoded_token = encode_token(&encode_matches).unwrap(); let decode_matcher = config_options() - .get_matches_from_safe(vec!["jwt", "decode", "-S", "1234567890", &encoded_token]) + .get_matches_from_safe(vec!["jwt", "verify", "-S", "1234567890", &encoded_token]) .unwrap(); - let decode_matches = decode_matcher.subcommand_matches("decode").unwrap(); - let (decoded_token, token_data, _) = decode_token(&decode_matches); + let decode_matches = decode_matcher.subcommand_matches("verify").unwrap(); + let (_, decoded_token, _) = decode_token(&decode_matches); - assert!(decoded_token.as_ref().unwrap().is_err()); + assert!(decoded_token.is_ok()); - let TokenData { claims, header: _ } = token_data.unwrap(); + let TokenData { claims, header: _ } = decoded_token.unwrap(); assert!(claims.0.get("exp").is_none()); } @@ -324,14 +326,16 @@ mod tests { let encode_matches = encode_matcher.subcommand_matches("encode").unwrap(); let encoded_token = encode_token(&encode_matches).unwrap(); let decode_matcher = config_options() - .get_matches_from_safe(vec!["jwt", "decode", "-S", "1234567890", &encoded_token]) + .get_matches_from_safe(vec!["jwt", "verify", "-S", "1234567890", &encoded_token]) .unwrap(); - let decode_matches = decode_matcher.subcommand_matches("decode").unwrap(); - let (decoded_token, _, _) = decode_token(&decode_matches); + let decode_matches = decode_matcher.subcommand_matches("verify").unwrap(); + let (jwt, decoded_token, _) = decode_token(&decode_matches); + let validated_token = verify_token(&jwt, &decode_matches); - assert!(decoded_token.as_ref().unwrap().is_ok()); + assert!(decoded_token.is_ok()); + assert!(validated_token.is_ok()); - let TokenData { claims, header: _ } = decoded_token.unwrap().unwrap(); + let TokenData { claims, header: _ } = decoded_token.unwrap(); let exp = from_value::(claims.0["exp"].clone()); assert!(exp.is_ok()); @@ -353,14 +357,14 @@ mod tests { let encode_matches = encode_matcher.subcommand_matches("encode").unwrap(); let encoded_token = encode_token(&encode_matches).unwrap(); let decode_matcher = config_options() - .get_matches_from_safe(vec!["jwt", "decode", "-S", "1234567890", &encoded_token]) + .get_matches_from_safe(vec!["jwt", "decode", &encoded_token]) .unwrap(); let decode_matches = decode_matcher.subcommand_matches("decode").unwrap(); - let (decoded_token, _, _) = decode_token(&decode_matches); + let (_, decoded_token, _) = decode_token(&decode_matches); - assert!(decoded_token.as_ref().unwrap().is_ok()); + assert!(decoded_token.is_ok()); - let TokenData { claims, header: _ } = decoded_token.unwrap().unwrap(); + let TokenData { claims, header: _ } = decoded_token.unwrap(); assert!(claims.0.get("iat").is_none()); } @@ -381,14 +385,14 @@ mod tests { let encode_matches = encode_matcher.subcommand_matches("encode").unwrap(); let encoded_token = encode_token(&encode_matches).unwrap(); let decode_matcher = config_options() - .get_matches_from_safe(vec!["jwt", "decode", "-S", "1234567890", &encoded_token]) + .get_matches_from_safe(vec!["jwt", "decode", &encoded_token]) .unwrap(); let decode_matches = decode_matcher.subcommand_matches("decode").unwrap(); - let (decoded_token, _, _) = decode_token(&decode_matches); + let (_, decoded_token, _) = decode_token(&decode_matches); - assert!(decoded_token.as_ref().unwrap().is_ok()); + assert!(decoded_token.is_ok()); - let TokenData { claims, header: _ } = decoded_token.unwrap().unwrap(); + let TokenData { claims, header: _ } = decoded_token.unwrap(); let exp_claim = from_value::(claims.0["exp"].clone()); assert!(exp_claim.is_ok()); @@ -403,12 +407,14 @@ mod tests { let encode_matches = encode_matcher.subcommand_matches("encode").unwrap(); let encoded_token = encode_token(&encode_matches).unwrap(); let decode_matcher = config_options() - .get_matches_from_safe(vec!["jwt", "decode", "-S", "1234567890", &encoded_token]) + .get_matches_from_safe(vec!["jwt", "verify", "-S", "1234567890", &encoded_token]) .unwrap(); - let decode_matches = decode_matcher.subcommand_matches("decode").unwrap(); - let (decoded_token, _, _) = decode_token(&decode_matches); + let decode_matches = decode_matcher.subcommand_matches("verify").unwrap(); + let (jwt, decoded_token, _) = decode_token(&decode_matches); + let validated_token = verify_token(&jwt, &decode_matches); - assert!(decoded_token.as_ref().unwrap().is_err()); + assert!(decoded_token.is_ok()); + assert!(validated_token.is_err()); } #[test] @@ -421,17 +427,19 @@ mod tests { let decode_matcher = config_options() .get_matches_from_safe(vec![ "jwt", - "decode", + "verify", "-S", "1234567890", "--ignore-exp", &encoded_token, ]) .unwrap(); - let decode_matches = decode_matcher.subcommand_matches("decode").unwrap(); - let (decoded_token, _, _) = decode_token(&decode_matches); + let decode_matches = decode_matcher.subcommand_matches("verify").unwrap(); + let (jwt, decoded_token, _) = decode_token(&decode_matches); + let validated_token = verify_token(&jwt, &decode_matches); - assert!(decoded_token.as_ref().unwrap().is_ok()); + assert!(decoded_token.is_ok()); + assert!(validated_token.is_ok()); } #[test] @@ -449,14 +457,16 @@ mod tests { let encode_matches = encode_matcher.subcommand_matches("encode").unwrap(); let encoded_token = encode_token(&encode_matches).unwrap(); let decode_matcher = config_options() - .get_matches_from_safe(vec!["jwt", "decode", "-S", "1234567890", &encoded_token]) + .get_matches_from_safe(vec!["jwt", "verify", "-S", "1234567890", &encoded_token]) .unwrap(); - let decode_matches = decode_matcher.subcommand_matches("decode").unwrap(); - let (decoded_token, _, _) = decode_token(&decode_matches); + let decode_matches = decode_matcher.subcommand_matches("verify").unwrap(); + let (jwt, decoded_token, _) = decode_token(&decode_matches); + let validated_token = verify_token(&jwt, &decode_matches); - assert!(decoded_token.as_ref().unwrap().is_ok()); + assert!(decoded_token.is_ok()); + assert!(validated_token.is_ok()); - let TokenData { claims, header: _ } = decoded_token.unwrap().unwrap(); + let TokenData { claims, header: _ } = decoded_token.unwrap(); let exp_claim = from_value::(claims.0["exp"].clone()); let iat_claim = from_value::(claims.0["iat"].clone()); @@ -485,14 +495,16 @@ mod tests { let encode_matches = encode_matcher.subcommand_matches("encode").unwrap(); let encoded_token = encode_token(&encode_matches).unwrap(); let decode_matcher = config_options() - .get_matches_from_safe(vec!["jwt", "decode", "-S", "1234567890", &encoded_token]) + .get_matches_from_safe(vec!["jwt", "verify", "-S", "1234567890", &encoded_token]) .unwrap(); - let decode_matches = decode_matcher.subcommand_matches("decode").unwrap(); - let (decoded_token, _, _) = decode_token(&decode_matches); + let decode_matches = decode_matcher.subcommand_matches("verify").unwrap(); + let (jwt, decoded_token, _) = decode_token(&decode_matches); + let validated_token = verify_token(&jwt, &decode_matches); - assert!(decoded_token.as_ref().unwrap().is_ok()); + assert!(decoded_token.is_ok()); + assert!(validated_token.is_ok()); - let TokenData { claims, header: _ } = decoded_token.unwrap().unwrap(); + let TokenData { claims, header: _ } = decoded_token.unwrap(); let nbf_claim = from_value::(claims.0["nbf"].clone()); let iat_claim = from_value::(claims.0["iat"].clone()); @@ -506,11 +518,11 @@ mod tests { } #[test] - fn decodes_a_token() { + fn validate_a_token() { let matches = config_options() .get_matches_from_safe(vec![ "jwt", - "decode", + "verify", "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE4OTM0NTYwMDAsImlhdCI6MTU0MjQ5MjMxMywidGhpcyI6InRoYXQifQ.YTWit46_AEMMVv0P48NeJJIqXmMHarGjfRxtR7jLlxE", "-S", "1234567890", @@ -518,10 +530,12 @@ mod tests { "HS256", ]) .unwrap(); - let decode_matches = matches.subcommand_matches("decode").unwrap(); - let (result, _, _) = decode_token(&decode_matches); + let decode_matches = matches.subcommand_matches("verify").unwrap(); + let (jwt, decoded_token, _) = decode_token(&decode_matches); + let validated_token = verify_token(&jwt, &decode_matches); - assert!(result.unwrap().is_ok()); + assert!(decoded_token.is_ok()); + assert!(validated_token.is_ok()); } #[test] @@ -535,19 +549,18 @@ mod tests { ]) .unwrap(); let decode_matches = matches.subcommand_matches("decode").unwrap(); - let (validated_token, token_data, format) = decode_token(&decode_matches); + let (_, decoded_token, format) = decode_token(&decode_matches); - assert!(validated_token.is_none()); // no signature validation - assert!(token_data.is_ok()); + assert!(decoded_token.is_ok()); assert!(format == OutputFormat::Json); } #[test] - fn decodes_a_token_with_invalid_secret() { + fn validates_a_token_with_invalid_secret() { let matches = config_options() .get_matches_from_safe(vec![ "jwt", - "decode", + "verify", "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0aGlzIjoidGhhdCJ9.AdAECLE_4iRa0uomMEdsMV2hDXv1vhLpym567-AzhrM", "-S", "yolo", @@ -555,44 +568,12 @@ mod tests { "HS256", ]) .unwrap(); - let decode_matches = matches.subcommand_matches("decode").unwrap(); - let (result, _, _) = decode_token(&decode_matches); - - assert!(result.unwrap().is_err()); - } - - #[test] - fn decodes_a_token_without_a_secret() { - let matches = config_options() - .get_matches_from_safe(vec![ - "jwt", - "decode", - "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0aGlzIjoidGhhdCJ9.AdAECLE_4iRa0uomMEdsMV2hDXv1vhLpym567-AzhrM", - "-A", - "HS256", - ]) - .unwrap(); - let decode_matches = matches.subcommand_matches("decode").unwrap(); - let (validated_token, token_data, _) = decode_token(&decode_matches); + let decode_matches = matches.subcommand_matches("verify").unwrap(); + let (jwt, decoded_token, _) = decode_token(&decode_matches); + let validated_token = verify_token(&jwt, &decode_matches); - assert!(validated_token.is_none()); // no signature validation - assert!(token_data.is_ok()); - } - - #[test] - fn decodes_a_token_without_an_alg() { - let matches = config_options() - .get_matches_from_safe(vec![ - "jwt", - "decode", - "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0aGlzIjoidGhhdCJ9.AdAECLE_4iRa0uomMEdsMV2hDXv1vhLpym567-AzhrM", - ]) - .unwrap(); - let decode_matches = matches.subcommand_matches("decode").unwrap(); - let (validated_token, token_data, _) = decode_token(&decode_matches); - - assert!(validated_token.is_none()); // no signature validation - assert!(token_data.is_ok()); + assert!(decoded_token.is_ok()); + assert!(validated_token.is_err()); } #[test] @@ -605,10 +586,9 @@ mod tests { ]) .unwrap(); let decode_matches = matches.subcommand_matches("decode").unwrap(); - let (validated_token, token_data, _) = decode_token(&decode_matches); + let (_, decoded_token, _) = decode_token(&decode_matches); - assert!(validated_token.is_none()); // no signature validation - assert!(token_data.is_ok()); + assert!(decoded_token.is_ok()); } #[test] @@ -621,10 +601,9 @@ mod tests { ]) .unwrap(); let decode_matches = matches.subcommand_matches("decode").unwrap(); - let (validated_token, token_data, _) = decode_token(&decode_matches); + let (_, decoded_token, _) = decode_token(&decode_matches); - assert!(validated_token.is_none()); // no signature validation - assert!(token_data.is_ok()); + assert!(decoded_token.is_ok()); } #[test] @@ -647,7 +626,7 @@ mod tests { let decode_matcher = config_options() .get_matches_from_safe(vec![ "jwt", - "decode", + "verify", "-S", "@./tests/public_rsa_key.der", "-A", @@ -655,10 +634,12 @@ mod tests { &encoded_token, ]) .unwrap(); - let decode_matches = decode_matcher.subcommand_matches("decode").unwrap(); - let (result, _, _) = decode_token(&decode_matches); + let decode_matches = decode_matcher.subcommand_matches("verify").unwrap(); + let (jwt, decoded_token, _) = decode_token(&decode_matches); + let validated_token = verify_token(&jwt, &decode_matches); - assert!(result.unwrap().is_ok()); + assert!(decoded_token.is_ok()); + assert!(validated_token.is_ok()); } #[test] @@ -694,7 +675,7 @@ mod tests { } #[test] - fn encodes_and_decodes_an_rsa_ssa_pss_token_using_key_from_file() { + fn encodes_and_verifies_an_rsa_ssa_pss_token_using_key_from_file() { let body: String = "{\"field\":\"value\"}".to_string(); let encode_matcher = config_options() .get_matches_from_safe(vec![ @@ -714,7 +695,7 @@ mod tests { let decode_matcher = config_options() .get_matches_from_safe(vec![ "jwt", - "decode", + "verify", "-S", "@./tests/public_rsa_key.der", "-A", @@ -722,19 +703,21 @@ mod tests { &encoded_token, ]) .unwrap(); - let decode_matches = decode_matcher.subcommand_matches("decode").unwrap(); - let (result, _, _) = decode_token(&decode_matches); + let decode_matches = decode_matcher.subcommand_matches("verify").unwrap(); + let (jwt, decoded_token, _) = decode_token(&decode_matches); + let validated_token = verify_token(&jwt, &decode_matches); - assert!(result.is_ok()); + assert!(decoded_token.is_ok()); + assert!(validated_token.is_ok()); } #[test] - fn decodes_an_rsa_ssa_pss_token_using_key_from_file() { + fn verify_an_rsa_ssa_pss_token_using_key_from_file() { let token: String = "eyJ0eXAiOiJKV1QiLCJhbGciOiJQUzUxMiJ9.eyJmaWVsZCI6InZhbHVlIiwiaWF0IjoxNjI1OTMxNjAwLCJleHAiOjkwMDAwMDAwMDB9.Tt1siDczvVAi89dH8QqTZ_n5Ejz4gAIzVLqucWN5tEqdAVRdWgP8psuRFdC8RKIn1Lp4OsUkAA7NJ79cZt32Eewy84hTYrCgZZ9mcWg5IfXPHcZmTUm6qSyKqANdsnRWThbG3IJSX1D6obI5Y91NhVI5PTRg8sFlDAXaNN9ZVTmAtZXj0b5-MgsjiRqWMW3xi9xQqTxvb5VN37Oot-KDWZXjkO022ixshzFWu8Jt582uMD4qYRp1d0VldgyGO_viDqqk8qTqNA7soUKWyDds0emuecE_bDMeELMfxMR-A1pQeu3FgEhliazIAdXJMNlwRuJG8znLNqCK1nB2Nd8sUQ".to_string(); let decode_matcher = config_options() .get_matches_from_safe(vec![ "jwt", - "decode", + "verify", "-S", "@./tests/public_rsa_key.der", "-A", @@ -742,10 +725,12 @@ mod tests { &token, ]) .unwrap(); - let decode_matches = decode_matcher.subcommand_matches("decode").unwrap(); - let (result, _, _) = decode_token(&decode_matches); + let decode_matches = decode_matcher.subcommand_matches("verify").unwrap(); + let (jwt, decoded_token, _) = decode_token(&decode_matches); + let validated_token = verify_token(&jwt, &decode_matches); - assert!(result.is_ok()); + assert!(decoded_token.is_ok()); + assert!(validated_token.is_ok()); } #[test] @@ -768,7 +753,7 @@ mod tests { let decode_matcher = config_options() .get_matches_from_safe(vec![ "jwt", - "decode", + "verify", "-S", "@./tests/public_ecdsa_key.pk8", "-A", @@ -776,10 +761,12 @@ mod tests { &encoded_token, ]) .unwrap(); - let decode_matches = decode_matcher.subcommand_matches("decode").unwrap(); - let (result, _, _) = decode_token(&decode_matches); + let decode_matches = decode_matcher.subcommand_matches("verify").unwrap(); + let (jwt, decoded_token, _) = decode_token(&decode_matches); + let validated_token = verify_token(&jwt, &decode_matches); - assert!(result.unwrap().is_ok()); + assert!(decoded_token.is_ok()); + assert!(validated_token.is_ok()); } #[test] @@ -801,21 +788,14 @@ mod tests { let encode_matches = encode_matcher.subcommand_matches("encode").unwrap(); let encoded_token = encode_token(&encode_matches).unwrap(); let decode_matcher = config_options() - .get_matches_from_safe(vec![ - "jwt", - "decode", - "-S", - "1234567890", - "--iso8601", - &encoded_token, - ]) + .get_matches_from_safe(vec!["jwt", "decode", "--iso8601", &encoded_token]) .unwrap(); let decode_matches = decode_matcher.subcommand_matches("decode").unwrap(); - let (decoded_token, token_data, _) = decode_token(&decode_matches); + let (_, decoded_token, _) = decode_token(&decode_matches); - assert!(decoded_token.as_ref().unwrap().is_ok()); + assert!(decoded_token.is_ok()); - let TokenData { claims, header: _ } = token_data.unwrap(); + let TokenData { claims, header: _ } = decoded_token.unwrap(); assert!(claims.0.get("iat").is_some()); assert!(claims.0.get("nbf").is_some()); From b22a3f6d7d53929bb31b867b88e34f91df23cb7c Mon Sep 17 00:00:00 2001 From: codedust Date: Thu, 21 Oct 2021 00:06:31 +0200 Subject: [PATCH 3/3] Fix clippy errors --- src/main.rs | 12 ++++++------ tests/jwt-cli.rs | 24 ++++++++++++------------ 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/main.rs b/src/main.rs index 1d63fff..18d5d8d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -541,7 +541,7 @@ fn decode_token(matches: &ArgMatches) -> (String, JWTResult>, ) } -fn verify_token(jwt: &String, matches: &ArgMatches) -> JWTResult> { +fn verify_token(jwt: String, matches: &ArgMatches) -> JWTResult> { let algorithm = translate_algorithm(SupportedAlgorithms::from_string( matches.value_of("algorithm").unwrap(), )); @@ -554,9 +554,9 @@ fn verify_token(jwt: &String, matches: &ArgMatches) -> JWTResult(jwt, &secret_key, &secret_validator) + decode::(&jwt, &secret_key, &secret_validator) } fn print_encoded_token(token: JWTResult) { @@ -669,7 +669,7 @@ fn main() { exit(return_code) } ("decode", Some(decode_matches)) => { - let (_, token_data, format) = decode_token(&decode_matches); + let (_, token_data, format) = decode_token(decode_matches); let return_code: i32 = match &token_data { Ok(_) => 0, // token decoded sucessfully Err(_) => 1, // token could not be decoded @@ -679,8 +679,8 @@ fn main() { exit(return_code) } ("verify", Some(decode_matches)) => { - let (jwt, token_data, format) = decode_token(&decode_matches); - let validated_token = verify_token(&jwt, &decode_matches); + let (jwt, token_data, format) = decode_token(decode_matches); + let validated_token = verify_token(jwt, decode_matches); let return_code: i32 = match validated_token { Ok(_) => 0, // successful signature check Err(_) => 1, // unsuccessful signature check diff --git a/tests/jwt-cli.rs b/tests/jwt-cli.rs index 9dacc2c..1978e3e 100644 --- a/tests/jwt-cli.rs +++ b/tests/jwt-cli.rs @@ -252,7 +252,7 @@ mod tests { .unwrap(); let decode_matches = decode_matcher.subcommand_matches("verify").unwrap(); let (jwt, token_data, _) = decode_token(&decode_matches); - let validated_token = verify_token(&jwt, &decode_matches); + let validated_token = verify_token(jwt, &decode_matches); assert!(token_data.is_ok()); assert!(validated_token.as_ref().is_ok()); @@ -330,7 +330,7 @@ mod tests { .unwrap(); let decode_matches = decode_matcher.subcommand_matches("verify").unwrap(); let (jwt, decoded_token, _) = decode_token(&decode_matches); - let validated_token = verify_token(&jwt, &decode_matches); + let validated_token = verify_token(jwt, &decode_matches); assert!(decoded_token.is_ok()); assert!(validated_token.is_ok()); @@ -411,7 +411,7 @@ mod tests { .unwrap(); let decode_matches = decode_matcher.subcommand_matches("verify").unwrap(); let (jwt, decoded_token, _) = decode_token(&decode_matches); - let validated_token = verify_token(&jwt, &decode_matches); + let validated_token = verify_token(jwt, &decode_matches); assert!(decoded_token.is_ok()); assert!(validated_token.is_err()); @@ -436,7 +436,7 @@ mod tests { .unwrap(); let decode_matches = decode_matcher.subcommand_matches("verify").unwrap(); let (jwt, decoded_token, _) = decode_token(&decode_matches); - let validated_token = verify_token(&jwt, &decode_matches); + let validated_token = verify_token(jwt, &decode_matches); assert!(decoded_token.is_ok()); assert!(validated_token.is_ok()); @@ -461,7 +461,7 @@ mod tests { .unwrap(); let decode_matches = decode_matcher.subcommand_matches("verify").unwrap(); let (jwt, decoded_token, _) = decode_token(&decode_matches); - let validated_token = verify_token(&jwt, &decode_matches); + let validated_token = verify_token(jwt, &decode_matches); assert!(decoded_token.is_ok()); assert!(validated_token.is_ok()); @@ -499,7 +499,7 @@ mod tests { .unwrap(); let decode_matches = decode_matcher.subcommand_matches("verify").unwrap(); let (jwt, decoded_token, _) = decode_token(&decode_matches); - let validated_token = verify_token(&jwt, &decode_matches); + let validated_token = verify_token(jwt, &decode_matches); assert!(decoded_token.is_ok()); assert!(validated_token.is_ok()); @@ -532,7 +532,7 @@ mod tests { .unwrap(); let decode_matches = matches.subcommand_matches("verify").unwrap(); let (jwt, decoded_token, _) = decode_token(&decode_matches); - let validated_token = verify_token(&jwt, &decode_matches); + let validated_token = verify_token(jwt, &decode_matches); assert!(decoded_token.is_ok()); assert!(validated_token.is_ok()); @@ -570,7 +570,7 @@ mod tests { .unwrap(); let decode_matches = matches.subcommand_matches("verify").unwrap(); let (jwt, decoded_token, _) = decode_token(&decode_matches); - let validated_token = verify_token(&jwt, &decode_matches); + let validated_token = verify_token(jwt, &decode_matches); assert!(decoded_token.is_ok()); assert!(validated_token.is_err()); @@ -636,7 +636,7 @@ mod tests { .unwrap(); let decode_matches = decode_matcher.subcommand_matches("verify").unwrap(); let (jwt, decoded_token, _) = decode_token(&decode_matches); - let validated_token = verify_token(&jwt, &decode_matches); + let validated_token = verify_token(jwt, &decode_matches); assert!(decoded_token.is_ok()); assert!(validated_token.is_ok()); @@ -705,7 +705,7 @@ mod tests { .unwrap(); let decode_matches = decode_matcher.subcommand_matches("verify").unwrap(); let (jwt, decoded_token, _) = decode_token(&decode_matches); - let validated_token = verify_token(&jwt, &decode_matches); + let validated_token = verify_token(jwt, &decode_matches); assert!(decoded_token.is_ok()); assert!(validated_token.is_ok()); @@ -727,7 +727,7 @@ mod tests { .unwrap(); let decode_matches = decode_matcher.subcommand_matches("verify").unwrap(); let (jwt, decoded_token, _) = decode_token(&decode_matches); - let validated_token = verify_token(&jwt, &decode_matches); + let validated_token = verify_token(jwt, &decode_matches); assert!(decoded_token.is_ok()); assert!(validated_token.is_ok()); @@ -763,7 +763,7 @@ mod tests { .unwrap(); let decode_matches = decode_matcher.subcommand_matches("verify").unwrap(); let (jwt, decoded_token, _) = decode_token(&decode_matches); - let validated_token = verify_token(&jwt, &decode_matches); + let validated_token = verify_token(jwt, &decode_matches); assert!(decoded_token.is_ok()); assert!(validated_token.is_ok());