Simplify header decoding
This commit is contained in:
parent
417e00780d
commit
73d96357c3
|
@ -45,7 +45,7 @@ pub enum ErrorKind {
|
|||
/// When a key is provided with an invalid format
|
||||
InvalidKeyFormat,
|
||||
|
||||
// validation error
|
||||
// Validation errors
|
||||
/// When a token’s `exp` claim indicates that it has expired
|
||||
ExpiredSignature,
|
||||
/// When a token’s `iss` claim does not match the expected issuer
|
||||
|
@ -91,6 +91,7 @@ impl StdError for Error {
|
|||
ErrorKind::InvalidSubject => "invalid subject",
|
||||
ErrorKind::ImmatureSignature => "immature signature",
|
||||
ErrorKind::InvalidAlgorithm => "algorithms don't match",
|
||||
ErrorKind::InvalidAlgorithmName => "not a known algorithm",
|
||||
ErrorKind::Base64(ref err) => err.description(),
|
||||
ErrorKind::Json(ref err) => err.description(),
|
||||
ErrorKind::Utf8(ref err) => err.description(),
|
||||
|
@ -111,6 +112,7 @@ impl StdError for Error {
|
|||
ErrorKind::InvalidSubject => None,
|
||||
ErrorKind::ImmatureSignature => None,
|
||||
ErrorKind::InvalidAlgorithm => None,
|
||||
ErrorKind::InvalidAlgorithmName => None,
|
||||
ErrorKind::Base64(ref err) => Some(err),
|
||||
ErrorKind::Json(ref err) => Some(err),
|
||||
ErrorKind::Utf8(ref err) => Some(err),
|
||||
|
@ -123,17 +125,17 @@ impl StdError for Error {
|
|||
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::InvalidEcdsaKey => write!(f, "invalid ECDSA key"),
|
||||
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::ImmatureSignature => write!(f, "immature signature"),
|
||||
ErrorKind::InvalidAlgorithm => write!(f, "algorithms don't match"),
|
||||
ErrorKind::Base64(ref err) => write!(f, "base64 error: {}", err),
|
||||
ErrorKind::InvalidToken
|
||||
| ErrorKind::InvalidSignature
|
||||
| ErrorKind::InvalidEcdsaKey
|
||||
| ErrorKind::InvalidRsaKey
|
||||
| ErrorKind::ExpiredSignature
|
||||
| ErrorKind::InvalidIssuer
|
||||
| ErrorKind::InvalidAudience
|
||||
| ErrorKind::InvalidSubject
|
||||
| ErrorKind::ImmatureSignature
|
||||
| ErrorKind::InvalidAlgorithm
|
||||
| ErrorKind::InvalidAlgorithmName => write!(f, "{}", self.description()),
|
||||
ErrorKind::Json(ref err) => write!(f, "JSON error: {}", err),
|
||||
ErrorKind::Utf8(ref err) => write!(f, "UTF-8 error: {}", err),
|
||||
ErrorKind::Crypto(ref err) => write!(f, "Crypto error: {}", err),
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
use crate::algorithms::Algorithm;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::algorithms::Algorithm;
|
||||
use crate::errors::Result;
|
||||
|
||||
/// A basic JWT header, the alg defaults to HS256 and typ is automatically
|
||||
/// set to `JWT`. All the other fields are optional.
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
|
@ -43,7 +45,7 @@ pub struct Header {
|
|||
|
||||
impl Header {
|
||||
/// Returns a JWT header with the algorithm given
|
||||
pub fn new(algorithm: Algorithm) -> Header {
|
||||
pub fn new(algorithm: Algorithm) -> Self {
|
||||
Header {
|
||||
typ: Some("JWT".to_string()),
|
||||
alg: algorithm,
|
||||
|
@ -54,6 +56,14 @@ impl Header {
|
|||
x5t: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts an encoded part into the Header struct if possible
|
||||
pub(crate) fn from_encoded(encoded_part: &str) -> Result<Self> {
|
||||
let decoded = base64::decode_config(encoded_part, base64::URL_SAFE_NO_PAD)?;
|
||||
let s = String::from_utf8(decoded)?;
|
||||
|
||||
Ok(serde_json::from_str(&s)?)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Header {
|
||||
|
|
12
src/lib.rs
12
src/lib.rs
|
@ -25,7 +25,7 @@ use serde::de::DeserializeOwned;
|
|||
use serde::ser::Serialize;
|
||||
|
||||
use crate::errors::{new_error, ErrorKind, Result};
|
||||
use crate::serialization::{from_jwt_part, from_jwt_part_claims, to_jwt_part};
|
||||
use crate::serialization::{encode_part, from_jwt_part_claims};
|
||||
use crate::validation::validate;
|
||||
|
||||
/// Encode the header and claims given and sign the payload using the algorithm from the header and the key
|
||||
|
@ -51,8 +51,8 @@ use crate::validation::validate;
|
|||
/// let token = encode(&Header::default(), &my_claims, Key::Hmac("secret".as_ref())).unwrap();
|
||||
/// ```
|
||||
pub fn encode<T: Serialize>(header: &Header, claims: &T, key: Key) -> Result<String> {
|
||||
let encoded_header = to_jwt_part(&header)?;
|
||||
let encoded_claims = to_jwt_part(&claims)?;
|
||||
let encoded_header = encode_part(&header)?;
|
||||
let encoded_claims = encode_part(&claims)?;
|
||||
let signing_input = [encoded_header.as_ref(), encoded_claims.as_ref()].join(".");
|
||||
let signature = sign(&*signing_input, key, header.alg)?;
|
||||
|
||||
|
@ -97,7 +97,7 @@ pub fn decode<T: DeserializeOwned>(
|
|||
) -> Result<TokenData<T>> {
|
||||
let (signature, signing_input) = expect_two!(token.rsplitn(2, '.'));
|
||||
let (claims, header) = expect_two!(signing_input.rsplitn(2, '.'));
|
||||
let header: Header = from_jwt_part(header)?;
|
||||
let header = Header::from_encoded(header)?;
|
||||
|
||||
if !verify(signature, signing_input, key, header.alg)? {
|
||||
return Err(new_error(ErrorKind::InvalidSignature));
|
||||
|
@ -135,7 +135,7 @@ pub fn decode<T: DeserializeOwned>(
|
|||
pub fn dangerous_unsafe_decode<T: DeserializeOwned>(token: &str) -> Result<TokenData<T>> {
|
||||
let (_, signing_input) = expect_two!(token.rsplitn(2, '.'));
|
||||
let (claims, header) = expect_two!(signing_input.rsplitn(2, '.'));
|
||||
let header: Header = from_jwt_part(header)?;
|
||||
let header = Header::from_encoded(header)?;
|
||||
|
||||
let (decoded_claims, _): (T, _) = from_jwt_part_claims(claims)?;
|
||||
|
||||
|
@ -156,7 +156,7 @@ pub fn dangerous_unsafe_decode<T: DeserializeOwned>(token: &str) -> Result<Token
|
|||
pub fn decode_header(token: &str) -> Result<Header> {
|
||||
let (_, signing_input) = expect_two!(token.rsplitn(2, '.'));
|
||||
let (_, header) = expect_two!(signing_input.rsplitn(2, '.'));
|
||||
from_jwt_part(header)
|
||||
Header::from_encoded(header)
|
||||
}
|
||||
|
||||
/// Decode a PEM string to obtain its key
|
||||
|
|
|
@ -16,18 +16,10 @@ pub struct TokenData<T> {
|
|||
pub claims: T,
|
||||
}
|
||||
|
||||
/// Serializes to JSON and encodes to base64
|
||||
pub fn to_jwt_part<T: Serialize>(input: &T) -> Result<String> {
|
||||
let encoded = to_string(input)?;
|
||||
Ok(base64::encode_config(encoded.as_bytes(), base64::URL_SAFE_NO_PAD))
|
||||
}
|
||||
|
||||
/// Decodes from base64 and deserializes from JSON to a struct
|
||||
pub fn from_jwt_part<B: AsRef<str>, T: DeserializeOwned>(encoded: B) -> Result<T> {
|
||||
let decoded = base64::decode_config(encoded.as_ref(), base64::URL_SAFE_NO_PAD)?;
|
||||
let s = String::from_utf8(decoded)?;
|
||||
|
||||
Ok(from_str(&s)?)
|
||||
/// Serializes a struct to JSON and encodes it in base64
|
||||
pub fn encode_part<T: Serialize>(input: &T) -> Result<String> {
|
||||
let json = to_string(input)?;
|
||||
Ok(base64::encode_config(json.as_bytes(), base64::URL_SAFE_NO_PAD))
|
||||
}
|
||||
|
||||
/// Decodes from base64 and deserializes from JSON to a struct AND a hashmap
|
||||
|
|
Loading…
Reference in New Issue