1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
use std::collections::BTreeMap;
use base64;
use serde_json;
use serde_json::Value as Json;
use Component;
use error::Error;
#[derive(Debug, Default, PartialEq)]
pub struct Claims {
pub reg: Registered,
pub private: BTreeMap<String, Json>,
}
#[derive(Debug, Default, PartialEq, Serialize, Deserialize)]
pub struct Registered {
pub iss: Option<String>,
pub sub: Option<String>,
pub aud: Option<String>,
pub exp: Option<u64>,
pub nbf: Option<u64>,
pub iat: Option<u64>,
pub jti: Option<String>,
}
impl Claims {
pub fn new(reg: Registered) -> Claims {
Claims {
reg: reg,
private: BTreeMap::new(),
}
}
}
impl Component for Claims {
fn from_base64(raw: &str) -> Result<Claims, Error> {
let data = base64::decode_config(raw, base64::URL_SAFE_NO_PAD)?;
let s = String::from_utf8(data)?;
let tree = match serde_json::from_str(&*s)? {
Json::Object(x) => x,
_ => return Err(Error::Format),
};
const FIELDS: [&'static str; 7] = ["iss", "sub", "aud", "exp", "nbf", "iat", "jti"];
let (_, pri): (BTreeMap<_, _>, BTreeMap<_, _>) = tree.into_iter()
.partition(|&(ref key, _)| FIELDS.iter().any(|f| f == key));
let reg_claims: Registered = serde_json::from_str(&*s)?;
Ok(Claims {
reg: reg_claims,
private: pri,
})
}
fn to_base64(&self) -> Result<String, Error> {
let s = serde_json::to_string(&self.reg)?;
let mut tree = match serde_json::from_str(&*s)? {
Json::Object(x) => x,
_ => return Err(Error::Format),
};
tree.extend(self.private.clone());
let s = serde_json::to_string(&tree)?;
let enc = base64::encode_config(&*s, base64::URL_SAFE_NO_PAD);
Ok(enc)
}
}
#[cfg(test)]
mod tests {
use std::default::Default;
use claims::{Claims, Registered};
use Component;
#[test]
fn from_base64() {
let enc = "ew0KICAiaXNzIjogIm1pa2t5YW5nLmNvbSIsDQogICJleHAiOiAxMzAyMzE5MTAwLA0KICAibmFtZSI6ICJNaWNoYWVsIFlhbmciLA0KICAiYWRtaW4iOiB0cnVlDQp9";
let claims = Claims::from_base64(enc).unwrap();
assert_eq!(claims.reg.iss.unwrap(), "mikkyang.com");
assert_eq!(claims.reg.exp.unwrap(), 1302319100);
}
#[test]
fn multiple_types() {
let enc = "ew0KICAiaXNzIjogIm1pa2t5YW5nLmNvbSIsDQogICJleHAiOiAxMzAyMzE5MTAwLA0KICAibmFtZSI6ICJNaWNoYWVsIFlhbmciLA0KICAiYWRtaW4iOiB0cnVlDQp9";
let claims = Registered::from_base64(enc).unwrap();
assert_eq!(claims.iss.unwrap(), "mikkyang.com");
assert_eq!(claims.exp.unwrap(), 1302319100);
}
#[test]
fn roundtrip() {
let mut claims: Claims = Default::default();
claims.reg.iss = Some("mikkyang.com".into());
claims.reg.exp = Some(1302319100);
let enc = claims.to_base64().unwrap();
assert_eq!(claims, Claims::from_base64(&*enc).unwrap());
}
}