Merge pull request #42 from Keats/next

Make it mandatory to specify algorithm
This commit is contained in:
Vincent Prouillet 2017-11-22 17:14:54 +01:00 committed by GitHub
commit 7a71501798
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 27 additions and 21 deletions

View File

@ -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"

View File

@ -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 validation: 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

View File

@ -29,7 +29,7 @@ fn main() {
};
println!("{:?}", token);
let token_data = match decode::<Claims>(&token, key.as_ref(), &Validation::default()) {
let token_data = match decode::<Claims>(&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

View File

@ -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::<Claims>(&token, key.as_ref(), &validation) {
Ok(c) => c,

View File

@ -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::<Claims>(&token, "secret", &Validation::default());
/// let token_data = decode::<Claims>(&token, "secret", &Validation::new(Algorithm::HS256));
/// ```
pub fn decode<T: DeserializeOwned>(token: &str, key: &[u8], validation: &Validation) -> Result<TokenData<T>> {
let (signature, signing_input) = expect_two!(token.rsplitn(2, '.'));
@ -111,10 +111,8 @@ pub fn decode<T: DeserializeOwned>(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)?;

View File

@ -67,14 +67,21 @@ pub struct Validation {
///
/// Defaults to `None`.
pub sub: Option<String>,
/// 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<Vec<Algorithm>>,
/// Defaults to `vec![Algorithm::HS256]`.
pub algorithms: Vec<Algorithm>,
}
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<T: Serialize>(&mut self, audience: &T) {
@ -95,7 +102,7 @@ impl Default for Validation {
sub: None,
aud: None,
algorithms: None,
algorithms: vec![Algorithm::HS256],
}
}
}

View File

@ -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::<Claims>(token, "secret".as_ref(), &Validation {algorithms: Some(vec![Algorithm::RS512]), ..Validation::default()});
let claims = decode::<Claims>(token, "secret".as_ref(), &Validation::new(Algorithm::RS512));
claims.unwrap();
}
@ -102,5 +102,4 @@ fn decode_header_only() {
let header = decode_header(token).unwrap();
assert_eq!(header.alg, Algorithm::HS256);
assert_eq!(header.typ, Some("JWT".to_string()));
}

View File

@ -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::<Claims>(&token, include_bytes!("public_rsa_key.der"), &Validation::default()).unwrap();
let token_data = decode::<Claims>(&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());
}