feat(claims): make RegisteredClaims serializable (fixes #38)

This commit is contained in:
cduvray 2023-11-03 07:52:36 +01:00
parent 6897633c7f
commit d3ccceef2c

View file

@ -1,8 +1,8 @@
use serde::Deserialize; use serde::{Deserialize, Serialize};
/// The number of seconds from 1970-01-01T00:00:00Z UTC until the specified UTC date/time ignoring leap seconds. /// The number of seconds from 1970-01-01T00:00:00Z UTC until the specified UTC date/time ignoring leap seconds.
/// (https://www.rfc-editor.org/rfc/rfc7519#section-2) /// (https://www.rfc-editor.org/rfc/rfc7519#section-2)
#[derive(Deserialize, Clone, PartialEq, Eq, Debug)] #[derive(Deserialize, Serialize, Clone, PartialEq, Eq, Debug)]
pub struct NumericDate(i64); pub struct NumericDate(i64);
/// accesses the underlying value /// accesses the underlying value
@ -32,7 +32,7 @@ impl From<NumericDate> for OffsetDateTime {
} }
} }
#[derive(PartialEq, Debug, Clone, Deserialize)] #[derive(PartialEq, Debug, Clone, Deserialize, Serialize)]
#[serde(untagged)] #[serde(untagged)]
pub enum OneOrArray<T> { pub enum OneOrArray<T> {
One(T), One(T),
@ -54,14 +54,21 @@ pub struct StringList(Vec<String>);
/// Claims mentioned in the JWT specifications. /// Claims mentioned in the JWT specifications.
/// ///
/// https://www.rfc-editor.org/rfc/rfc7519#section-4.1 /// https://www.rfc-editor.org/rfc/rfc7519#section-4.1
#[derive(Deserialize, Clone, Debug)] #[derive(Deserialize, Serialize, Clone, Debug)]
pub struct RegisteredClaims { pub struct RegisteredClaims {
#[serde(skip_serializing_if = "Option::is_none")]
pub iss: Option<String>, pub iss: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub sub: Option<String>, pub sub: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub aud: Option<OneOrArray<String>>, pub aud: Option<OneOrArray<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub exp: Option<NumericDate>, pub exp: Option<NumericDate>,
#[serde(skip_serializing_if = "Option::is_none")]
pub nbf: Option<NumericDate>, pub nbf: Option<NumericDate>,
#[serde(skip_serializing_if = "Option::is_none")]
pub iat: Option<NumericDate>, pub iat: Option<NumericDate>,
#[serde(skip_serializing_if = "Option::is_none")]
pub jti: Option<String>, pub jti: Option<String>,
} }
@ -146,8 +153,28 @@ mod tests {
OneOrArray::Array(vec!["aud1".to_owned(), "aud2".to_owned()]) OneOrArray::Array(vec!["aud1".to_owned(), "aud2".to_owned()])
); );
assert_eq!(claims.exp.unwrap(), NumericDate(1516240122)); assert_eq!(claims.exp.unwrap(), NumericDate(1516240122));
assert_eq!(claims.nbf, None);
let dt: DateTime<Utc> = claims.iat.unwrap().into(); let dt: DateTime<Utc> = claims.iat.unwrap().into();
assert_eq!(dt, Utc.timestamp_opt(1516239022, 0).unwrap()); assert_eq!(dt, Utc.timestamp_opt(1516239022, 0).unwrap());
} }
#[test]
fn rfc_claims_serde() {
let claims_str = r#"{
"iss": "http://localhost:3001",
"sub": "bob",
"aud": ["aud1", "aud2"],
"exp": 1516240122,
"iat": 1516239022
}"#;
let claims: RegisteredClaims = serde_json::from_str(claims_str).expect("Failed RfcClaims deserialisation");
// assert_eq!(claims.iss.unwrap(), "http://localhost:3001");
let jwt_serd = serde_json::to_string(&claims).unwrap();
let mut trimed_claims = claims_str.to_owned();
trimed_claims.retain(|c| !c.is_whitespace());
assert_eq!(trimed_claims, jwt_serd);
}
} }