use std::marker::PhantomData;
use super::scopes::ClaimScope;
use super::{AuthError, Claims, VerifyConfig};
use crate::KeySet;
use crate::engine::check_id_token_claims::{self, RegisteredClaims};
use crate::engine::shared_error::SharedAuthError;
use crate::engine::{
check_acr, check_algorithm, check_at_hash, check_auth_time, check_azp, check_c_hash,
check_header, check_id_token_cat, check_id_token_pii, check_nonce, check_signature, raw,
};
pub async fn verify<S: ClaimScope>(
token: &str,
cfg: &VerifyConfig,
key_set: &KeySet,
now: i64,
) -> Result<Claims<S>, AuthError> {
if token.len() > cfg.shared.max_token_size {
return Err(AuthError::Jose(SharedAuthError::OversizedToken));
}
if token.starts_with('{') {
return Err(AuthError::Jose(SharedAuthError::JwsJsonRejected));
}
if token.split('.').count() == 5 {
return Err(AuthError::Jose(SharedAuthError::JwePayload));
}
check_algorithm::run(token, &cfg.shared)?;
let key = check_header::run(token, &cfg.shared, key_set)?;
check_signature::run(token, key)?;
let payload = raw::parse_payload_json(token)?;
check_id_token_cat::run(&payload)?;
let registered = check_id_token_claims::run(&payload, cfg, now)?;
check_nonce::run(&payload, &cfg.expected_nonce)?;
check_at_hash::run(&payload, cfg)?;
check_c_hash::run(&payload, cfg)?;
check_azp::run(&payload, cfg)?;
check_auth_time::run(&payload, cfg, now)?;
check_acr::run(&payload, cfg)?;
check_id_token_pii::run(&payload, S::claim_names())?;
Ok(deserialize_claims::<S>(
&payload,
registered,
cfg.expected_nonce.as_str(),
))
}
fn deserialize_claims<S: ClaimScope>(
payload: &serde_json::Value,
registered: RegisteredClaims,
nonce: &str,
) -> Claims<S> {
let s = |key: &str| payload.get(key).and_then(|v| v.as_str()).map(str::to_owned);
let i = |key: &str| payload.get(key).and_then(serde_json::Value::as_i64);
let b = |key: &str| payload.get(key).and_then(serde_json::Value::as_bool);
let RegisteredClaims {
iss,
sub,
aud,
exp,
iat,
} = registered;
let amr = payload.get("amr").and_then(|v| v.as_array()).map(|a| {
a.iter()
.filter_map(|v| v.as_str().map(str::to_owned))
.collect()
});
Claims {
iss,
sub,
aud,
exp,
iat,
nonce: nonce.to_owned(),
azp: s("azp"),
auth_time: i("auth_time"),
acr: s("acr"),
amr,
email: s("email"),
email_verified: b("email_verified"),
name: s("name"),
given_name: s("given_name"),
family_name: s("family_name"),
middle_name: s("middle_name"),
nickname: s("nickname"),
preferred_username: s("preferred_username"),
profile: s("profile"),
picture: s("picture"),
website: s("website"),
gender: s("gender"),
birthdate: s("birthdate"),
zoneinfo: s("zoneinfo"),
locale: s("locale"),
updated_at: i("updated_at"),
_scope: PhantomData,
}
}