Remove error-chain

Fix #52, #56, #57
This commit is contained in:
Vincent Prouillet 2018-07-25 14:43:58 +02:00
parent 126ee4b1a3
commit 109978ab6b
6 changed files with 176 additions and 78 deletions

View File

@ -1,7 +1,14 @@
# Changelog
## 5.0.0 (unreleased)
- Update ring
- Change error handling to be based on simple struct/enum rather than error-chain
## 4.0.1 (2018-03-19)
- Add method to decode a token without signature verification
## 4.0.0 (2017-11-22)
### Breaking changes

View File

@ -1,6 +1,6 @@
[package]
name = "jsonwebtoken"
version = "4.0.1"
version = "5.0.0"
authors = ["Vincent Prouillet <prouillet.vincent@gmail.com>"]
license = "MIT"
readme = "README.md"
@ -10,7 +10,6 @@ repository = "https://github.com/Keats/rust-jwt"
keywords = ["jwt", "web", "api", "token", "json"]
[dependencies]
error-chain = { version = "0.11", default-features = false }
serde_json = "1.0"
serde_derive = "1.0"
serde = "1.0"

View File

@ -48,14 +48,14 @@ fn sign_rsa(alg: Algorithm, key: &[u8], signing_input: &str) -> Result<String> {
let key_pair = Arc::new(
signature::RSAKeyPair::from_der(untrusted::Input::from(key))
.map_err(|_| ErrorKind::InvalidKey)?
.map_err(|_| ErrorKind::InvalidRsaKey)?
);
let mut signing_state = signature::RSASigningState::new(key_pair)
.map_err(|_| ErrorKind::InvalidKey)?;
.map_err(|_| ErrorKind::InvalidRsaKey)?;
let mut signature = vec![0; signing_state.key_pair().public_modulus_len()];
let rng = rand::SystemRandom::new();
signing_state.sign(ring_alg, &rng, signing_input.as_bytes(), &mut signature)
.map_err(|_| ErrorKind::InvalidKey)?;
.map_err(|_| ErrorKind::InvalidRsaKey)?;
Ok(
base64::encode_config::<[u8]>(&signature, base64::URL_SAFE_NO_PAD)
@ -73,7 +73,7 @@ pub fn sign(signing_input: &str, key: &[u8], algorithm: Algorithm) -> Result<Str
Algorithm::HS512 => sign_hmac(&digest::SHA512, key, signing_input),
Algorithm::RS256 | Algorithm::RS384 | Algorithm::RS512 => sign_rsa(algorithm, key, signing_input),
// TODO: if PKCS1 is made prublic, remove the line above and uncomment below
// TODO: if PKCS1 is made public, remove the line above and uncomment below
// Algorithm::RS256 => sign_rsa(&signature::RSA_PKCS1_SHA256, key, signing_input),
// Algorithm::RS384 => sign_rsa(&signature::RSA_PKCS1_SHA384, key, signing_input),
// Algorithm::RS512 => sign_rsa(&signature::RSA_PKCS1_SHA512, key, signing_input),

View File

@ -1,68 +1,162 @@
use std::error::Error as StdError;
use std::fmt;
use std::result;
use base64;
use serde_json;
use ring;
error_chain! {
errors {
/// When a token doesn't have a valid JWT shape
InvalidToken {
description("invalid token")
display("Invalid token")
}
/// When the signature doesn't match
InvalidSignature {
description("invalid signature")
display("Invalid signature")
}
/// When the secret given is not a valid RSA key
InvalidKey {
description("invalid key")
display("Invalid Key")
}
/// A crate private constructor for `Error`.
pub(crate) fn new_error(kind: ErrorKind) -> Error {
Error(Box::new(kind))
}
// Validation error
/// When a tokens `exp` claim indicates that it has expired
ExpiredSignature {
description("expired signature")
display("Expired Signature")
}
/// When a tokens `iss` claim does not match the expected issuer
InvalidIssuer {
description("invalid issuer")
display("Invalid Issuer")
}
/// When a tokens `aud` claim does not match one of the expected audience values
InvalidAudience {
description("invalid audience")
display("Invalid Audience")
}
/// When a tokens `aud` claim does not match one of the expected audience values
InvalidSubject {
description("invalid subject")
display("Invalid Subject")
}
/// When a tokens `iat` claim is in the future
InvalidIssuedAt {
description("invalid issued at")
display("Invalid Issued At")
}
/// When a tokens nbf claim represents a time in the future
ImmatureSignature {
description("immature signature")
display("Immature Signature")
}
/// When the algorithm in the header doesn't match the one passed to `decode`
InvalidAlgorithm {
description("Invalid algorithm")
display("Invalid Algorithm")
}
/// A type alias for `Result<T, jsonwebtoken::Error>`.
pub type Result<T> = result::Result<T, Error>;
/// An error that can occur when encoding/decoding JWTs
#[derive(Debug)]
pub struct Error(Box<ErrorKind>);
impl Error {
/// Return the specific type of this error.
pub fn kind(&self) -> &ErrorKind {
&self.0
}
foreign_links {
Unspecified(ring::error::Unspecified) #[doc = "An error happened while signing/verifying a token with RSA"];
Base64(base64::DecodeError) #[doc = "An error happened while decoding some base64 text"];
Json(serde_json::Error) #[doc = "An error happened while serializing/deserializing JSON"];
Utf8(::std::string::FromUtf8Error) #[doc = "An error happened while trying to convert the result of base64 decoding to a String"];
/// Unwrap this error into its underlying type.
pub fn into_kind(self) -> ErrorKind {
*self.0
}
}
/// The specific type of an error.
#[derive(Debug)]
pub enum ErrorKind {
/// When a token doesn't have a valid JWT shape
InvalidToken,
/// When the signature doesn't match
InvalidSignature,
/// When the secret given is not a valid RSA key
InvalidRsaKey,
// validation error
/// When a tokens `exp` claim indicates that it has expired
ExpiredSignature,
/// When a tokens `iss` claim does not match the expected issuer
InvalidIssuer,
/// When a tokens `aud` claim does not match one of the expected audience values
InvalidAudience,
/// When a tokens `aud` claim does not match one of the expected audience values
InvalidSubject,
/// When a tokens `iat` claim is in the future
InvalidIssuedAt,
/// When a tokens nbf claim represents a time in the future
ImmatureSignature,
/// When the algorithm in the header doesn't match the one passed to `decode`
InvalidAlgorithm,
// 3rd party errors
/// An error happened when decoding some base64 text
Base64(base64::DecodeError),
/// An error happened while serializing/deserializing JSON
Json(serde_json::Error),
/// Some of the text was invalid UTF-8
Utf8(::std::string::FromUtf8Error),
/// Hints that destructuring should not be exhaustive.
///
/// This enum may grow additional variants, so this makes sure clients
/// don't count on exhaustive matching. (Otherwise, adding a new variant
/// could break existing code.)
#[doc(hidden)]
__Nonexhaustive,
}
impl StdError for Error {
fn description(&self) -> &str {
match *self.0 {
ErrorKind::InvalidToken => "invalid token",
ErrorKind::InvalidSignature => "invalid signature",
ErrorKind::InvalidRsaKey => "invalid RSA key",
ErrorKind::ExpiredSignature => "expired signature",
ErrorKind::InvalidIssuer => "invalid issuer",
ErrorKind::InvalidAudience => "invalid audience",
ErrorKind::InvalidSubject => "invalid subject",
ErrorKind::InvalidIssuedAt => "invalid issued at",
ErrorKind::ImmatureSignature => "immature signature",
ErrorKind::InvalidAlgorithm => "algorithms don't match",
ErrorKind::Base64(ref err) => err.description(),
ErrorKind::Json(ref err) => err.description(),
ErrorKind::Utf8(ref err) => err.description(),
_ => unreachable!(),
}
}
fn cause(&self) -> Option<&StdError> {
match *self.0 {
ErrorKind::InvalidToken => None,
ErrorKind::InvalidSignature => None,
ErrorKind::InvalidRsaKey => None,
ErrorKind::ExpiredSignature => None,
ErrorKind::InvalidIssuer => None,
ErrorKind::InvalidAudience => None,
ErrorKind::InvalidSubject => None,
ErrorKind::InvalidIssuedAt => None,
ErrorKind::ImmatureSignature => None,
ErrorKind::InvalidAlgorithm => None,
ErrorKind::Base64(ref err) => Some(err),
ErrorKind::Json(ref err) => Some(err),
ErrorKind::Utf8(ref err) => Some(err),
_ => unreachable!(),
}
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self.0 {
ErrorKind::InvalidToken => write!(f, "invalid token"),
ErrorKind::InvalidSignature => write!(f, "invalid signature"),
ErrorKind::InvalidRsaKey => write!(f, "invalid RSA key"),
ErrorKind::ExpiredSignature => write!(f, "expired signature"),
ErrorKind::InvalidIssuer => write!(f, "invalid issuer"),
ErrorKind::InvalidAudience => write!(f, "invalid audience"),
ErrorKind::InvalidSubject => write!(f, "invalid subject"),
ErrorKind::InvalidIssuedAt => write!(f, "invalid issued at"),
ErrorKind::ImmatureSignature => write!(f, "immature signature"),
ErrorKind::InvalidAlgorithm => write!(f, "algorithms don't match"),
ErrorKind::Base64(ref err) => write!(f, "base64 error: {}", err),
ErrorKind::Json(ref err) => write!(f, "JSON error: {}", err),
ErrorKind::Utf8(ref err) => write!(f, "UTF-8 error: {}", err),
_ => unreachable!(),
}
}
}
impl From<base64::DecodeError> for Error {
fn from(err: base64::DecodeError) -> Error {
new_error(ErrorKind::Base64(err))
}
}
impl From<serde_json::Error> for Error {
fn from(err: serde_json::Error) -> Error {
new_error(ErrorKind::Json(err))
}
}
impl From<::std::string::FromUtf8Error> for Error {
fn from(err: ::std::string::FromUtf8Error) -> Error {
new_error(ErrorKind::Utf8(err))
}
}
impl From<ErrorKind> for Error {
fn from(kind: ErrorKind) -> Error {
new_error(kind)
}
}

View File

@ -4,8 +4,6 @@
#![recursion_limit = "300"]
#![deny(missing_docs)]
#[macro_use]
extern crate error_chain;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
@ -35,7 +33,7 @@ pub use serialization::TokenData;
use serde::de::DeserializeOwned;
use serde::ser::Serialize;
use errors::{Result, ErrorKind};
use errors::{Result, ErrorKind, new_error};
use serialization::{from_jwt_part, from_jwt_part_claims, to_jwt_part};
use validation::{validate};
@ -78,7 +76,7 @@ macro_rules! expect_two {
let mut i = $iter;
match (i.next(), i.next(), i.next()) {
(Some(first), Some(second), None) => (first, second),
_ => return Err(ErrorKind::InvalidToken.into())
_ => return Err(new_error(ErrorKind::InvalidToken))
}
}}
}
@ -108,11 +106,11 @@ pub fn decode<T: DeserializeOwned>(token: &str, key: &[u8], validation: &Validat
let header: Header = from_jwt_part(header)?;
if !verify(signature, signing_input, key, header.alg)? {
return Err(ErrorKind::InvalidSignature.into());
return Err(new_error(ErrorKind::InvalidSignature));
}
if !validation.algorithms.contains(&header.alg) {
return Err(ErrorKind::InvalidAlgorithm.into());
return Err(new_error(ErrorKind::InvalidAlgorithm));
}
let (decoded_claims, claims_map): (T, _) = from_jwt_part_claims(claims)?;

View File

@ -3,7 +3,7 @@ use serde::ser::Serialize;
use serde_json::{Value, from_value, to_value};
use serde_json::map::Map;
use errors::{Result, ErrorKind};
use errors::{Result, ErrorKind, new_error};
use crypto::Algorithm;
@ -114,26 +114,26 @@ pub fn validate(claims: &Map<String, Value>, options: &Validation) -> Result<()>
if let Some(iat) = claims.get("iat") {
if options.validate_iat && from_value::<i64>(iat.clone())? > now + options.leeway {
return Err(ErrorKind::InvalidIssuedAt.into());
return Err(new_error(ErrorKind::InvalidIssuedAt));
}
}
if let Some(exp) = claims.get("exp") {
if options.validate_exp && from_value::<i64>(exp.clone())? < now - options.leeway {
return Err(ErrorKind::ExpiredSignature.into());
return Err(new_error(ErrorKind::ExpiredSignature));
}
}
if let Some(nbf) = claims.get("nbf") {
if options.validate_nbf && from_value::<i64>(nbf.clone())? > now + options.leeway {
return Err(ErrorKind::ImmatureSignature.into());
return Err(new_error(ErrorKind::ImmatureSignature));
}
}
if let Some(iss) = claims.get("iss") {
if let Some(ref correct_iss) = options.iss {
if from_value::<String>(iss.clone())? != *correct_iss {
return Err(ErrorKind::InvalidIssuer.into());
return Err(new_error(ErrorKind::InvalidIssuer));
}
}
}
@ -141,7 +141,7 @@ pub fn validate(claims: &Map<String, Value>, options: &Validation) -> Result<()>
if let Some(sub) = claims.get("sub") {
if let Some(ref correct_sub) = options.sub {
if from_value::<String>(sub.clone())? != *correct_sub {
return Err(ErrorKind::InvalidSubject.into());
return Err(new_error(ErrorKind::InvalidSubject));
}
}
}
@ -149,7 +149,7 @@ pub fn validate(claims: &Map<String, Value>, options: &Validation) -> Result<()>
if let Some(aud) = claims.get("aud") {
if let Some(ref correct_aud) = options.aud {
if aud != correct_aud {
return Err(ErrorKind::InvalidAudience.into());
return Err(new_error(ErrorKind::InvalidAudience));
}
}
}