pub mod v0;
pub mod v1;
use std::time::SystemTime;
use scion_sdk_token_validator::validator::Token;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize)]
#[serde(untagged)]
pub enum AnyClaims {
V1(v1::SnapTokenClaims),
V0(v0::SnapTokenClaims),
}
impl<'de> Deserialize<'de> for AnyClaims {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let value = serde_json::Value::deserialize(deserializer)?;
if let Some(ver) = value.get("ver") {
match ver.as_u64() {
Some(1) => {
let claims: v1::SnapTokenClaims =
serde_json::from_value(value).map_err(serde::de::Error::custom)?;
Ok(AnyClaims::V1(claims))
}
Some(n) => {
Err(serde::de::Error::custom(format!(
"unsupported SNAP token version: {}",
n
)))
}
None => {
Err(serde::de::Error::custom(
"invalid SNAP token: 'ver' claim must be a number",
))
}
}
} else {
let claims: v0::SnapTokenClaims =
serde_json::from_value(value).map_err(serde::de::Error::custom)?;
Ok(AnyClaims::V0(claims))
}
}
}
impl AnyClaims {
pub fn pssid(&self) -> String {
match self {
AnyClaims::V1(c) => c.pssid.to_string(),
AnyClaims::V0(c) => c.pssid.to_string(),
}
}
pub fn jti(&self) -> String {
match self {
AnyClaims::V1(c) => c.jti.clone(),
AnyClaims::V0(c) => c.jti.clone(),
}
}
}
impl Token for AnyClaims {
fn id(&self) -> String {
match self {
Self::V1(c) => c.id(),
Self::V0(c) => c.id(),
}
}
fn exp_time(&self) -> SystemTime {
match self {
Self::V1(c) => c.exp_time(),
Self::V0(c) => c.exp_time(),
}
}
fn required_claims() -> Vec<&'static str> {
vec!["exp", "pssid"]
}
}
#[cfg(test)]
mod tests {
use serde_json::json;
use super::*;
#[test]
fn test_any_claims_dispatch() {
let v0_json = json!({
"jti": "jti_v0",
"exp": 2000000000,
"pssid": "ef16640f-0fa9-4360-be74-dbeec7ab4f9a"
});
let c: AnyClaims = serde_json::from_value(v0_json).expect("should parse as V0");
assert!(matches!(c, AnyClaims::V0(_)));
let v1_json = json!({
"ver": 1,
"jti": "jti_v1",
"iss": "ssr",
"aud": "snap",
"exp": 2000000000,
"nbf": 1000,
"iat": 1000,
"pssid": "AAAAAAAAAAAAAAAAAAAAAAA",
"aa_acc_subject_id": "subj",
"aa_acc_allowed_dst": "[]"
});
let c: AnyClaims = serde_json::from_value(v1_json).expect("should parse as V1");
assert!(matches!(c, AnyClaims::V1(_)));
let v2_json = json!({
"ver": 2,
"exp": 2000000000
});
let err = serde_json::from_value::<AnyClaims>(v2_json).unwrap_err();
assert!(
err.to_string()
.contains("unsupported SNAP token version: 2")
);
}
}