Can define additional claims on per-client basis
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
@ -1,5 +1,8 @@
|
||||
use crate::data::entity_manager::EntityManager;
|
||||
use crate::data::user::User;
|
||||
use crate::utils::string_utils::apply_env_vars;
|
||||
use serde_json::Value;
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize, Eq, PartialEq)]
|
||||
pub struct ClientID(pub String);
|
||||
@ -10,6 +13,8 @@ pub enum AuthenticationFlow {
|
||||
Implicit,
|
||||
}
|
||||
|
||||
pub type AdditionalClaims = HashMap<String, Value>;
|
||||
|
||||
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
|
||||
pub struct Client {
|
||||
/// The ID of the client
|
||||
@ -39,6 +44,12 @@ pub struct Client {
|
||||
/// Specify whether recent Second Factor Authentication is required to access this client
|
||||
#[serde(default = "bool::default")]
|
||||
pub enforce_2fa_auth: bool,
|
||||
|
||||
/// Additional claims to return with the id token
|
||||
claims_id_token: Option<AdditionalClaims>,
|
||||
|
||||
/// Additional claims to return through the user info endpoint
|
||||
claims_user_info: Option<AdditionalClaims>,
|
||||
}
|
||||
|
||||
impl PartialEq for Client {
|
||||
@ -57,6 +68,68 @@ impl Client {
|
||||
Some(_) => AuthenticationFlow::AuthorizationCode,
|
||||
}
|
||||
}
|
||||
|
||||
/// Process a single claim value
|
||||
fn process_claim_string(&self, user: &User, str: &str) -> String {
|
||||
str.replace("{username}", &user.username)
|
||||
.replace("{mail}", &user.email)
|
||||
.replace("{first_name}", &user.first_name)
|
||||
.replace("{last_name}", &user.last_name)
|
||||
.replace("{uid}", &user.uid.0)
|
||||
}
|
||||
|
||||
/// Recurse claims processing
|
||||
fn recurse_claims_processing(&self, user: &User, value: &Value) -> Value {
|
||||
match value {
|
||||
Value::String(s) => Value::String(self.process_claim_string(user, s)),
|
||||
Value::Array(arr) => Value::Array(
|
||||
arr.iter()
|
||||
.map(|v| self.recurse_claims_processing(user, v))
|
||||
.collect(),
|
||||
),
|
||||
Value::Object(obj) => obj
|
||||
.iter()
|
||||
.map(|(k, v)| {
|
||||
(
|
||||
self.process_claim_string(user, k),
|
||||
self.recurse_claims_processing(user, v),
|
||||
)
|
||||
})
|
||||
.collect(),
|
||||
v => v.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Process additional claims, processing placeholders
|
||||
fn process_additional_claims(
|
||||
&self,
|
||||
user: &User,
|
||||
claims: &Option<AdditionalClaims>,
|
||||
) -> Option<AdditionalClaims> {
|
||||
let claims = claims.as_ref()?;
|
||||
|
||||
let res = claims
|
||||
.iter()
|
||||
.map(|(k, v)| {
|
||||
(
|
||||
self.process_claim_string(user, k),
|
||||
self.recurse_claims_processing(user, v),
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
|
||||
Some(res)
|
||||
}
|
||||
|
||||
/// Get additional claims for id_token for a successful authentication
|
||||
pub fn claims_id_token(&self, user: &User) -> Option<AdditionalClaims> {
|
||||
self.process_additional_claims(user, &self.claims_id_token)
|
||||
}
|
||||
|
||||
/// Get additional claims for user info for a successful authentication
|
||||
pub fn claims_user_info(&self, user: &User) -> Option<AdditionalClaims> {
|
||||
self.process_additional_claims(user, &self.claims_user_info)
|
||||
}
|
||||
}
|
||||
|
||||
pub type ClientManager = EntityManager<Client>;
|
||||
|
@ -1,3 +1,4 @@
|
||||
use crate::data::client::AdditionalClaims;
|
||||
use jwt_simple::claims::Audiences;
|
||||
use jwt_simple::prelude::{Duration, JWTClaims};
|
||||
|
||||
@ -24,12 +25,19 @@ pub struct IdToken {
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub nonce: Option<String>,
|
||||
pub email: String,
|
||||
/// Additional claims
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[serde(flatten)]
|
||||
pub additional_claims: Option<AdditionalClaims>,
|
||||
}
|
||||
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
pub struct CustomIdTokenClaims {
|
||||
auth_time: u64,
|
||||
email: String,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[serde(flatten)]
|
||||
additional_claims: Option<AdditionalClaims>,
|
||||
}
|
||||
|
||||
impl IdToken {
|
||||
@ -46,6 +54,7 @@ impl IdToken {
|
||||
custom: CustomIdTokenClaims {
|
||||
auth_time: self.auth_time,
|
||||
email: self.email,
|
||||
additional_claims: self.additional_claims,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user