use super::*;
use std::{future::Future, pin::Pin, sync::Arc};
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
#[serde(untagged)]
pub enum JwtAudience {
Single(String),
Multiple(Vec<String>),
}
impl From<String> for JwtAudience {
fn from(value: String) -> Self {
Self::Single(value)
}
}
impl From<&str> for JwtAudience {
fn from(value: &str) -> Self {
Self::Single(value.into())
}
}
impl From<Vec<String>> for JwtAudience {
fn from(value: Vec<String>) -> Self {
Self::Multiple(value)
}
}
impl JwtAudience {
pub(super) fn recipients(&self) -> Vec<&str> {
match self {
Self::Single(value) => vec![value],
Self::Multiple(values) => values.iter().map(String::as_str).collect(),
}
}
}
#[derive(Clone, Debug)]
pub enum JwtExpiration {
After(Duration),
At(serde_json::Number),
}
impl From<Duration> for JwtExpiration {
fn from(value: Duration) -> Self {
Self::After(value)
}
}
impl From<chrono::DateTime<Utc>> for JwtExpiration {
fn from(value: chrono::DateTime<Utc>) -> Self {
Self::At(value.timestamp().into())
}
}
impl From<i64> for JwtExpiration {
fn from(value: i64) -> Self {
Self::At(value.into())
}
}
pub type JwtCallbackFuture<T> = Pin<Box<dyn Future<Output = AuthResult<T>> + Send>>;
pub type JwtDefinePayload =
Arc<dyn Fn(Value) -> JwtCallbackFuture<Map<String, Value>> + Send + Sync>;
pub type JwtGetSubject = Arc<dyn Fn(Value) -> JwtCallbackFuture<String> + Send + Sync>;
pub type JwtCustomSign =
Arc<dyn Fn(Map<String, Value>, JwtSigningOptions) -> JwtCallbackFuture<String> + Send + Sync>;
pub type JwtNativeDefinePayload =
Arc<dyn Fn(FieldValue) -> JwtCallbackFuture<FieldValue> + Send + Sync>;
pub type JwtNativeGetSubject =
Arc<dyn Fn(FieldValue) -> JwtCallbackFuture<FieldValue> + Send + Sync>;
pub type JwtNativeCustomSign =
Arc<dyn Fn(FieldValue, FieldValue, FieldValue) -> JwtCallbackFuture<FieldValue> + Send + Sync>;
impl JwtPlugin {
pub fn define_payload(self, callback: JwtDefinePayload) -> Self {
self.define_payload_native(Arc::new(move |session| {
let callback = callback.clone();
Box::pin(async move {
Ok(FieldMap::from_json(callback(callback_json(&session)?).await?)?.into())
})
}))
}
pub fn define_payload_native(mut self, callback: JwtNativeDefinePayload) -> Self {
self.config.define_payload = Some(callback);
self
}
pub fn get_subject(self, callback: JwtGetSubject) -> Self {
self.get_subject_native(Arc::new(move |session| {
let callback = callback.clone();
Box::pin(async move { Ok(callback(callback_json(&session)?).await?.into()) })
}))
}
pub fn get_subject_native(mut self, callback: JwtNativeGetSubject) -> Self {
self.config.get_subject = Some(callback);
self
}
pub fn custom_sign(self, callback: JwtCustomSign) -> Self {
self.custom_sign_native(Arc::new(move |payload, header, selection| {
let callback = callback.clone();
Box::pin(async move {
let payload = serde_json::from_value(callback_json(&payload)?)?;
let key = selection.model_property("signingKeyId")?;
let algorithm = selection.model_property("signingAlgorithm")?;
let options = JwtSigningOptions {
key_id: key.json()?.map(serde_json::from_value).transpose()?,
algorithm: algorithm.json()?.map(serde_json::from_value).transpose()?,
header: if header.is_undefined() {
Map::new()
} else {
serde_json::from_value(callback_json(&header)?)?
},
};
Ok(callback(payload, options).await?.into())
})
}))
}
pub fn custom_sign_native(mut self, callback: JwtNativeCustomSign) -> Self {
self.config.custom_sign = Some(callback);
self
}
}
fn callback_json(value: &FieldValue) -> AuthResult<Value> {
value.json()?.ok_or_else(|| {
AuthError::type_error("The JSON JWT callback input has no JSON representation")
})
}
#[derive(Clone, Debug, Default)]
pub struct JwtSigningOptions {
pub key_id: Option<String>,
pub algorithm: Option<JwtAlgorithm>,
pub header: Map<String, Value>,
}
#[derive(Clone, Copy, Debug, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct JwtKeyPairConfig {
#[serde(rename = "alg")]
pub algorithm: JwtAlgorithm,
#[serde(default = "default_modulus_length")]
pub modulus_length: u32,
}
impl JwtKeyPairConfig {
pub fn new(algorithm: JwtAlgorithm) -> Self {
Self {
algorithm,
modulus_length: 2048,
}
}
}
fn default_modulus_length() -> u32 {
2048
}