Merge branch 'next' into master
This commit is contained in:
commit
b4e0ae5f6d
|
@ -1,5 +1,10 @@
|
||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 6.0.0 (unreleased)
|
||||||
|
|
||||||
|
- Update Ring to 0.14
|
||||||
|
- Remove `iat` check to match the JWT spec
|
||||||
|
|
||||||
## 5.0.1 (2018-09-10)
|
## 5.0.1 (2018-09-10)
|
||||||
|
|
||||||
- Add implementation of FromStr for Algorithm
|
- Add implementation of FromStr for Algorithm
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "jsonwebtoken"
|
name = "jsonwebtoken"
|
||||||
version = "5.0.1"
|
version = "6.0.0"
|
||||||
authors = ["Vincent Prouillet <prouillet.vincent@gmail.com>"]
|
authors = ["Vincent Prouillet <prouillet.vincent@gmail.com>"]
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
Add the following to Cargo.toml:
|
Add the following to Cargo.toml:
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
jsonwebtoken = "5"
|
jsonwebtoken = "6"
|
||||||
serde_derive = "1"
|
serde_derive = "1"
|
||||||
serde = "1"
|
serde = "1"
|
||||||
```
|
```
|
||||||
|
@ -72,7 +72,7 @@ let header = decode_header(&token)?;
|
||||||
This does not perform any validation on the token.
|
This does not perform any validation on the token.
|
||||||
|
|
||||||
#### Validation
|
#### Validation
|
||||||
This library validates automatically the `iat`, `exp` and `nbf` claims if present. You can also validate the `sub`, `iss` and `aud` but
|
This library validates automatically the `exp` and `nbf` claims if present. You can also validate the `sub`, `iss` and `aud` but
|
||||||
those require setting the expected value in the `Validation` struct.
|
those require setting the expected value in the `Validation` struct.
|
||||||
|
|
||||||
Since validating time fields is always a bit tricky due to clock skew,
|
Since validating time fields is always a bit tricky due to clock skew,
|
||||||
|
@ -87,7 +87,7 @@ use jsonwebtoken::{Validation, Algorithm};
|
||||||
let validation = Validation::default();
|
let validation = Validation::default();
|
||||||
// Quick way to setup a validation where only the algorithm changes
|
// Quick way to setup a validation where only the algorithm changes
|
||||||
let validation = Validation::new(Algorithm::HS512);
|
let validation = Validation::new(Algorithm::HS512);
|
||||||
// Adding some leeway (in seconds) for iat, exp and nbf checks
|
// Adding some leeway (in seconds) for exp and nbf checks
|
||||||
let mut validation = Validation {leeway: 60, ..Default::default()};
|
let mut validation = Validation {leeway: 60, ..Default::default()};
|
||||||
// Checking issuer
|
// Checking issuer
|
||||||
let mut validation = Validation {iss: Some("issuer".to_string()), ..Default::default()};
|
let mut validation = Validation {iss: Some("issuer".to_string()), ..Default::default()};
|
||||||
|
|
|
@ -52,8 +52,6 @@ pub enum ErrorKind {
|
||||||
InvalidAudience,
|
InvalidAudience,
|
||||||
/// When a token’s `aud` claim does not match one of the expected audience values
|
/// When a token’s `aud` claim does not match one of the expected audience values
|
||||||
InvalidSubject,
|
InvalidSubject,
|
||||||
/// When a token’s `iat` claim is in the future
|
|
||||||
InvalidIssuedAt,
|
|
||||||
/// When a token’s nbf claim represents a time in the future
|
/// When a token’s nbf claim represents a time in the future
|
||||||
ImmatureSignature,
|
ImmatureSignature,
|
||||||
/// When the algorithm in the header doesn't match the one passed to `decode`
|
/// When the algorithm in the header doesn't match the one passed to `decode`
|
||||||
|
@ -89,7 +87,6 @@ impl StdError for Error {
|
||||||
ErrorKind::InvalidIssuer => "invalid issuer",
|
ErrorKind::InvalidIssuer => "invalid issuer",
|
||||||
ErrorKind::InvalidAudience => "invalid audience",
|
ErrorKind::InvalidAudience => "invalid audience",
|
||||||
ErrorKind::InvalidSubject => "invalid subject",
|
ErrorKind::InvalidSubject => "invalid subject",
|
||||||
ErrorKind::InvalidIssuedAt => "invalid issued at",
|
|
||||||
ErrorKind::ImmatureSignature => "immature signature",
|
ErrorKind::ImmatureSignature => "immature signature",
|
||||||
ErrorKind::InvalidAlgorithm => "algorithms don't match",
|
ErrorKind::InvalidAlgorithm => "algorithms don't match",
|
||||||
ErrorKind::Base64(ref err) => err.description(),
|
ErrorKind::Base64(ref err) => err.description(),
|
||||||
|
@ -110,7 +107,6 @@ impl StdError for Error {
|
||||||
ErrorKind::InvalidIssuer => None,
|
ErrorKind::InvalidIssuer => None,
|
||||||
ErrorKind::InvalidAudience => None,
|
ErrorKind::InvalidAudience => None,
|
||||||
ErrorKind::InvalidSubject => None,
|
ErrorKind::InvalidSubject => None,
|
||||||
ErrorKind::InvalidIssuedAt => None,
|
|
||||||
ErrorKind::ImmatureSignature => None,
|
ErrorKind::ImmatureSignature => None,
|
||||||
ErrorKind::InvalidAlgorithm => None,
|
ErrorKind::InvalidAlgorithm => None,
|
||||||
ErrorKind::Base64(ref err) => Some(err),
|
ErrorKind::Base64(ref err) => Some(err),
|
||||||
|
@ -133,7 +129,6 @@ impl fmt::Display for Error {
|
||||||
ErrorKind::InvalidIssuer => write!(f, "invalid issuer"),
|
ErrorKind::InvalidIssuer => write!(f, "invalid issuer"),
|
||||||
ErrorKind::InvalidAudience => write!(f, "invalid audience"),
|
ErrorKind::InvalidAudience => write!(f, "invalid audience"),
|
||||||
ErrorKind::InvalidSubject => write!(f, "invalid subject"),
|
ErrorKind::InvalidSubject => write!(f, "invalid subject"),
|
||||||
ErrorKind::InvalidIssuedAt => write!(f, "invalid issued at"),
|
|
||||||
ErrorKind::ImmatureSignature => write!(f, "immature signature"),
|
ErrorKind::ImmatureSignature => write!(f, "immature signature"),
|
||||||
ErrorKind::InvalidAlgorithm => write!(f, "algorithms don't match"),
|
ErrorKind::InvalidAlgorithm => write!(f, "algorithms don't match"),
|
||||||
ErrorKind::Base64(ref err) => write!(f, "base64 error: {}", err),
|
ErrorKind::Base64(ref err) => write!(f, "base64 error: {}", err),
|
||||||
|
|
|
@ -37,17 +37,11 @@ pub struct Validation {
|
||||||
///
|
///
|
||||||
/// Defaults to `true`.
|
/// Defaults to `true`.
|
||||||
pub validate_exp: bool,
|
pub validate_exp: bool,
|
||||||
/// Whether to validate the `iat` field.
|
|
||||||
///
|
|
||||||
/// It will return an error if the time in the `iat` field is in the future.
|
|
||||||
///
|
|
||||||
/// Defaults to `true`.
|
|
||||||
pub validate_iat: bool,
|
|
||||||
/// Whether to validate the `nbf` field.
|
/// Whether to validate the `nbf` field.
|
||||||
///
|
///
|
||||||
/// It will return an error if the current timestamp is before the time in the `nbf` field.
|
/// It will return an error if the current timestamp is before the time in the `nbf` field.
|
||||||
///
|
///
|
||||||
/// Defaults to `true`.
|
/// Defaults to `false`.
|
||||||
pub validate_nbf: bool,
|
pub validate_nbf: bool,
|
||||||
/// If it contains a value, the validation will check that the `aud` field is the same as the
|
/// If it contains a value, the validation will check that the `aud` field is the same as the
|
||||||
/// one provided and will error otherwise.
|
/// one provided and will error otherwise.
|
||||||
|
@ -94,7 +88,6 @@ impl Default for Validation {
|
||||||
leeway: 0,
|
leeway: 0,
|
||||||
|
|
||||||
validate_exp: true,
|
validate_exp: true,
|
||||||
validate_iat: false,
|
|
||||||
validate_nbf: false,
|
validate_nbf: false,
|
||||||
|
|
||||||
iss: None,
|
iss: None,
|
||||||
|
@ -109,16 +102,6 @@ impl Default for Validation {
|
||||||
pub fn validate(claims: &Map<String, Value>, options: &Validation) -> Result<()> {
|
pub fn validate(claims: &Map<String, Value>, options: &Validation) -> Result<()> {
|
||||||
let now = Utc::now().timestamp();
|
let now = Utc::now().timestamp();
|
||||||
|
|
||||||
if options.validate_iat {
|
|
||||||
if let Some(iat) = claims.get("iat") {
|
|
||||||
if from_value::<i64>(iat.clone())? > now + options.leeway {
|
|
||||||
return Err(new_error(ErrorKind::InvalidIssuedAt));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return Err(new_error(ErrorKind::InvalidIssuedAt));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if options.validate_exp {
|
if options.validate_exp {
|
||||||
if let Some(exp) = claims.get("exp") {
|
if let Some(exp) = claims.get("exp") {
|
||||||
if from_value::<i64>(exp.clone())? < now - options.leeway {
|
if from_value::<i64>(exp.clone())? < now - options.leeway {
|
||||||
|
@ -182,45 +165,6 @@ mod tests {
|
||||||
|
|
||||||
use errors::ErrorKind;
|
use errors::ErrorKind;
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn iat_in_past_ok() {
|
|
||||||
let mut claims = Map::new();
|
|
||||||
claims.insert("iat".to_string(), to_value(Utc::now().timestamp() - 10000).unwrap());
|
|
||||||
let validation =
|
|
||||||
Validation { validate_exp: false, validate_iat: true, ..Validation::default() };
|
|
||||||
let res = validate(&claims, &validation);
|
|
||||||
assert!(res.is_ok());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn iat_in_future_fails() {
|
|
||||||
let mut claims = Map::new();
|
|
||||||
claims.insert("iat".to_string(), to_value(Utc::now().timestamp() + 100000).unwrap());
|
|
||||||
let validation =
|
|
||||||
Validation { validate_exp: false, validate_iat: true, ..Validation::default() };
|
|
||||||
let res = validate(&claims, &validation);
|
|
||||||
assert!(res.is_err());
|
|
||||||
|
|
||||||
match res.unwrap_err().kind() {
|
|
||||||
&ErrorKind::InvalidIssuedAt => (),
|
|
||||||
_ => assert!(false),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn iat_in_future_but_in_leeway_ok() {
|
|
||||||
let mut claims = Map::new();
|
|
||||||
claims.insert("iat".to_string(), to_value(Utc::now().timestamp() + 50).unwrap());
|
|
||||||
let validation = Validation {
|
|
||||||
leeway: 1000 * 60,
|
|
||||||
validate_iat: true,
|
|
||||||
validate_exp: false,
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
let res = validate(&claims, &validation);
|
|
||||||
assert!(res.is_ok());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn exp_in_future_ok() {
|
fn exp_in_future_ok() {
|
||||||
let mut claims = Map::new();
|
let mut claims = Map::new();
|
||||||
|
|
Loading…
Reference in New Issue