rust_cfzt_validator/
app_token.rs

1use crate::{
2    errors::{UnpackError, UnpackResult},
3    unpack, DecodedToken,
4};
5
6/// Represents the common claims included in the CFZT JWT
7pub struct ApplicationToken {
8    pub email: String,
9    pub exp: u64,
10    pub iat: u64,
11    pub nbf: u64,
12    pub iss: String,
13    pub sub: String,
14    pub country: String,
15    pub custom: unpack::JsonObject,
16    pub headers: jsonwebtoken::Header,
17}
18
19impl ApplicationToken {
20    // Consumes a `TokenData<Value>` emitted by a successful `Validator.validate_token()`
21    // and returns an ApplicationToken struct.
22    pub fn from_token_data(token_data: DecodedToken) -> UnpackResult<Self> {
23        let claims = unpack::as_object(&token_data.claims)?;
24
25        let get_str_claim = |key: &str| -> UnpackResult<String> {
26            Ok(unpack::as_string(unpack::get_key(claims, key)?)?.clone())
27        };
28
29        let get_uint_claim = |key: &str| -> UnpackResult<u64> {
30            let num = unpack::as_number(unpack::get_key(claims, key)?)?;
31            num.as_u64().ok_or(UnpackError::number_parse_failure("u64"))
32        };
33
34        let get_obj_claim = |key: &str| -> UnpackResult<unpack::JsonObject> {
35            Ok(unpack::as_object(unpack::get_key(claims, key)?)?.to_owned())
36        };
37
38        Ok(ApplicationToken {
39            email: get_str_claim("email")?,
40            exp: get_uint_claim("exp")?,
41            iat: get_uint_claim("iat")?,
42            nbf: get_uint_claim("nbf")?,
43            iss: get_str_claim("iss")?,
44            sub: get_str_claim("sub")?,
45            country: get_str_claim("country")?,
46            custom: get_obj_claim("custom")?,
47            headers: token_data.header,
48        })
49    }
50}
51
52#[cfg(test)]
53mod tests {
54    use super::*;
55    use crate::{
56        api::TeamKeys,
57        {TeamValidator, Validator},
58    };
59
60    const TEAM_NAME: &str = "molten";
61    const AUDIENCE: &str = "41f1d879c797d912d9bd80710db3dce92d30602a2dcbdf7bab33913071c44bd4";
62    const APPLICATION_TOKEN_JWT: &str = "eyJhbGciOiJSUzI1NiIsImtpZCI6ImE1ZWE4YmQxYjk0Y2FkZjJhNWYwZjQ3ZGFkMTg4ZTZhYWZiY2QyOGVlYWIyZTcxYjExZGRkOTZkOWNjMjhjNjkifQ.eyJhdWQiOlsiNDFmMWQ4NzljNzk3ZDkxMmQ5YmQ4MDcxMGRiM2RjZTkyZDMwNjAyYTJkY2JkZjdiYWIzMzkxMzA3MWM0NGJkNCJdLCJlbWFpbCI6Im1lQGphY29idGF5bG9yLmlkLmF1IiwiZXhwIjoxNzE3OTgxNDM5LCJpYXQiOjE3MTc5Nzk2MzksIm5iZiI6MTcxNzk3OTYzOSwiaXNzIjoiaHR0cHM6Ly9tb2x0ZW4uY2xvdWRmbGFyZWFjY2Vzcy5jb20iLCJ0eXBlIjoiYXBwIiwiaWRlbnRpdHlfbm9uY2UiOiJBUFhHRnFsT2k5OVNsVVF3Iiwic3ViIjoiNzIwOGVlYTQtNDA5OC01YTMxLTkwNTMtZjA5YjgxYzI4MWZkIiwiY3VzdG9tIjp7ImVtYWlsIjoiIn0sImNvdW50cnkiOiJBVSJ9.nwTTyb2ioh5Fw39zKyBMZJuj0wzxOuP2KxsbzDLQCmOBNekTvhmquAui3bmuwpzhTTfjxP9yAJG1_N0Hmc-h613E8jOQclqAVgr9_JEYPZ2v58exPRgjeokEIQweRYKgLgoqHAqaYTKQ4v8-pHeRL66L-2Ui3uVUi8V8PkeJogKfPHvFjnkCqZPFFpuxkW735x0Vxq5CzQesoHH37hLAJe7ckc4Jav1AholNsLOvlBIxZtC9ET8-3YqO5rOUCqSX_6oKmf0VyOmqzbSw4gaXvnaTBAPiGruU63gg_LsV0NVGeVvddy84Tl3WvQvbPwdCJ9W9KsbkyOryfgbL0lrZPA";
63    const SIGNING_KEYS_JSON: &str = include_str!("../test_data/sample_signing_keys.json");
64
65    fn get_validator() -> Box<dyn Validator> {
66        let agent = ureq::agent();
67        let keys = TeamKeys::from_str(TEAM_NAME, SIGNING_KEYS_JSON).unwrap();
68        let validator = TeamValidator::from_team_keys(keys, agent);
69        Box::new(validator)
70    }
71
72    #[test]
73    fn test_application_token() {
74        let validator = get_validator();
75
76        let mut constraints = jsonwebtoken::Validation::new(jsonwebtoken::Algorithm::RS256);
77        constraints.validate_nbf = false;
78        constraints.validate_exp = false;
79        constraints.set_audience(&[AUDIENCE]);
80
81        let result = validator.validate_token(APPLICATION_TOKEN_JWT, TEAM_NAME, &mut constraints);
82        assert!(result.is_ok());
83
84        let app_token = ApplicationToken::from_token_data(result.unwrap()).unwrap();
85
86        assert_eq!(app_token.exp, 1717981439);
87        assert_eq!(app_token.iat, 1717979639);
88        assert_eq!(app_token.nbf, 1717979639);
89        assert_eq!(app_token.iss, "https://molten.cloudflareaccess.com");
90        assert_eq!(app_token.sub, "7208eea4-4098-5a31-9053-f09b81c281fd");
91        assert_eq!(app_token.country, "AU")
92    }
93}