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:
		
							
								
								
									
										58
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										58
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							@@ -106,7 +106,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "quote",
 | 
			
		||||
 "syn 2.0.55",
 | 
			
		||||
 "syn 2.0.57",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
@@ -246,7 +246,7 @@ dependencies = [
 | 
			
		||||
 "actix-router",
 | 
			
		||||
 "proc-macro2",
 | 
			
		||||
 "quote",
 | 
			
		||||
 "syn 2.0.55",
 | 
			
		||||
 "syn 2.0.57",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
@@ -257,7 +257,7 @@ checksum = "7c7db3d5a9718568e4cf4a537cfd7070e6e6ff7481510d0237fb529ac850f6d3"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "proc-macro2",
 | 
			
		||||
 "quote",
 | 
			
		||||
 "syn 2.0.55",
 | 
			
		||||
 "syn 2.0.57",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
@@ -460,7 +460,7 @@ dependencies = [
 | 
			
		||||
 "proc-macro2",
 | 
			
		||||
 "quote",
 | 
			
		||||
 "serde",
 | 
			
		||||
 "syn 2.0.55",
 | 
			
		||||
 "syn 2.0.57",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
@@ -845,7 +845,7 @@ dependencies = [
 | 
			
		||||
 "heck",
 | 
			
		||||
 "proc-macro2",
 | 
			
		||||
 "quote",
 | 
			
		||||
 "syn 2.0.55",
 | 
			
		||||
 "syn 2.0.57",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
@@ -1090,7 +1090,7 @@ checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "proc-macro2",
 | 
			
		||||
 "quote",
 | 
			
		||||
 "syn 2.0.55",
 | 
			
		||||
 "syn 2.0.57",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
@@ -1283,7 +1283,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "proc-macro2",
 | 
			
		||||
 "quote",
 | 
			
		||||
 "syn 2.0.55",
 | 
			
		||||
 "syn 2.0.57",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
@@ -1723,7 +1723,7 @@ dependencies = [
 | 
			
		||||
 "proc-macro2",
 | 
			
		||||
 "quote",
 | 
			
		||||
 "regex",
 | 
			
		||||
 "syn 2.0.55",
 | 
			
		||||
 "syn 2.0.57",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
@@ -1815,9 +1815,9 @@ dependencies = [
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "memchr"
 | 
			
		||||
version = "2.7.1"
 | 
			
		||||
version = "2.7.2"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149"
 | 
			
		||||
checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "mime"
 | 
			
		||||
@@ -2008,7 +2008,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "proc-macro2",
 | 
			
		||||
 "quote",
 | 
			
		||||
 "syn 2.0.55",
 | 
			
		||||
 "syn 2.0.57",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
@@ -2019,9 +2019,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "openssl-sys"
 | 
			
		||||
version = "0.9.101"
 | 
			
		||||
version = "0.9.102"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "dda2b0f344e78efc2facf7d195d098df0dd72151b26ab98da807afc26c198dff"
 | 
			
		||||
checksum = "c597637d56fbc83893a35eb0dd04b2b8e7a50c91e64e9493e398b5df4fb45fa2"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "cc",
 | 
			
		||||
 "libc",
 | 
			
		||||
@@ -2099,9 +2099,9 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "pin-project-lite"
 | 
			
		||||
version = "0.2.13"
 | 
			
		||||
version = "0.2.14"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58"
 | 
			
		||||
checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "pin-utils"
 | 
			
		||||
@@ -2454,9 +2454,9 @@ dependencies = [
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "security-framework"
 | 
			
		||||
version = "2.9.2"
 | 
			
		||||
version = "2.10.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de"
 | 
			
		||||
checksum = "770452e37cad93e0a50d5abc3990d2bc351c36d0328f86cefec2f2fb206eaef6"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "bitflags 1.3.2",
 | 
			
		||||
 "core-foundation",
 | 
			
		||||
@@ -2467,9 +2467,9 @@ dependencies = [
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "security-framework-sys"
 | 
			
		||||
version = "2.9.1"
 | 
			
		||||
version = "2.10.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a"
 | 
			
		||||
checksum = "41f3cc463c0ef97e11c3461a9d3787412d30e8e7eb907c79180c4a57bf7c04ef"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "core-foundation-sys",
 | 
			
		||||
 "libc",
 | 
			
		||||
@@ -2508,7 +2508,7 @@ checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "proc-macro2",
 | 
			
		||||
 "quote",
 | 
			
		||||
 "syn 2.0.55",
 | 
			
		||||
 "syn 2.0.57",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
@@ -2673,9 +2673,9 @@ dependencies = [
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "syn"
 | 
			
		||||
version = "2.0.55"
 | 
			
		||||
version = "2.0.57"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "002a1b3dbf967edfafc32655d0f377ab0bb7b994aa1d32c8cc7e9b8bf3ebb8f0"
 | 
			
		||||
checksum = "11a6ae1e52eb25aab8f3fb9fca13be982a373b8f1157ca14b897a825ba4a2d35"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "proc-macro2",
 | 
			
		||||
 "quote",
 | 
			
		||||
@@ -2750,7 +2750,7 @@ checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "proc-macro2",
 | 
			
		||||
 "quote",
 | 
			
		||||
 "syn 2.0.55",
 | 
			
		||||
 "syn 2.0.57",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
@@ -2801,9 +2801,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "tokio"
 | 
			
		||||
version = "1.36.0"
 | 
			
		||||
version = "1.37.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "61285f6515fa018fb2d1e46eb21223fff441ee8db5d0f1435e8ab4f5cdb80931"
 | 
			
		||||
checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "backtrace",
 | 
			
		||||
 "bytes",
 | 
			
		||||
@@ -2875,7 +2875,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "proc-macro2",
 | 
			
		||||
 "quote",
 | 
			
		||||
 "syn 2.0.55",
 | 
			
		||||
 "syn 2.0.57",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
@@ -3060,7 +3060,7 @@ dependencies = [
 | 
			
		||||
 "once_cell",
 | 
			
		||||
 "proc-macro2",
 | 
			
		||||
 "quote",
 | 
			
		||||
 "syn 2.0.55",
 | 
			
		||||
 "syn 2.0.57",
 | 
			
		||||
 "wasm-bindgen-shared",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
@@ -3094,7 +3094,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "proc-macro2",
 | 
			
		||||
 "quote",
 | 
			
		||||
 "syn 2.0.55",
 | 
			
		||||
 "syn 2.0.57",
 | 
			
		||||
 "wasm-bindgen-backend",
 | 
			
		||||
 "wasm-bindgen-shared",
 | 
			
		||||
]
 | 
			
		||||
@@ -3373,7 +3373,7 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "proc-macro2",
 | 
			
		||||
 "quote",
 | 
			
		||||
 "syn 2.0.55",
 | 
			
		||||
 "syn 2.0.57",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										21
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										21
									
								
								README.md
									
									
									
									
									
								
							@@ -23,12 +23,27 @@ You can configure a list of clients (Relying Parties) in a `clients.yaml` file w
 | 
			
		||||
  secret: TOP_SECRET
 | 
			
		||||
  # The URL where user shall be redirected after authentication
 | 
			
		||||
  redirect_uri: https://mygit.mywebsite.com/
 | 
			
		||||
  # If you want new accounts to be granted access to this client by default
 | 
			
		||||
  # Optional, If you want new accounts to be granted access to this client by default
 | 
			
		||||
  default: true
 | 
			
		||||
  # If you want the client to be granted to every user, regardless their account configuration
 | 
			
		||||
  # Optional, If you want the client to be granted to every user, regardless their account configuration
 | 
			
		||||
  granted_to_all_users: true
 | 
			
		||||
  # If you want users to have performed recent second factor authentication before accessing this client, set this setting to true
 | 
			
		||||
  # Optional, If you want users to have performed recent second factor authentication before accessing this client, set this setting to true
 | 
			
		||||
  enforce_2fa_auth: true
 | 
			
		||||
  # Optional, claims to be added to the ID token payload.
 | 
			
		||||
  # The following placeholders can be set, they will the replaced when the token is created:
 | 
			
		||||
  # * {username}: user name of the user
 | 
			
		||||
  # * {mail}: email address of the user
 | 
			
		||||
  # * {first_name}: first name of the user
 | 
			
		||||
  # * {last_name}: last name of the user
 | 
			
		||||
  # * {uid}: user id of the user
 | 
			
		||||
  claims_id_token:
 | 
			
		||||
    groups: ["group_{user}"]
 | 
			
		||||
    service: "auth"
 | 
			
		||||
  # Optional, claims to be added to the user info endpoint response
 | 
			
		||||
  # The placeholders of `claims_id_token` can also be used here 
 | 
			
		||||
  claims_user_info:
 | 
			
		||||
    groups: ["group_{user}"]
 | 
			
		||||
    service: "auth"
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
On the first run, BasicOIDC will create a new administrator with credentials `admin` / `admin`. On first login you will have to change these default credentials.
 | 
			
		||||
 
 | 
			
		||||
@@ -16,7 +16,7 @@ use crate::constants::*;
 | 
			
		||||
use crate::controllers::base_controller::{build_fatal_error_page, redirect_user};
 | 
			
		||||
use crate::data::action_logger::{Action, ActionLogger};
 | 
			
		||||
use crate::data::app_config::AppConfig;
 | 
			
		||||
use crate::data::client::{AuthenticationFlow, ClientID, ClientManager};
 | 
			
		||||
use crate::data::client::{AdditionalClaims, AuthenticationFlow, ClientID, ClientManager};
 | 
			
		||||
use crate::data::code_challenge::CodeChallenge;
 | 
			
		||||
use crate::data::current_user::CurrentUser;
 | 
			
		||||
use crate::data::id_token::IdToken;
 | 
			
		||||
@@ -270,6 +270,7 @@ pub async fn authorize(
 | 
			
		||||
                auth_time: SessionIdentity(Some(&id)).auth_time(),
 | 
			
		||||
                nonce: query.nonce.clone(),
 | 
			
		||||
                email: user.email.clone(),
 | 
			
		||||
                additional_claims: client.claims_id_token(&user),
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            log::trace!("New OpenID id token: {:#?}", &id_token);
 | 
			
		||||
@@ -533,7 +534,8 @@ pub async fn token(
 | 
			
		||||
                issued_at: time(),
 | 
			
		||||
                auth_time: session.auth_time,
 | 
			
		||||
                nonce: session.nonce,
 | 
			
		||||
                email: user.email,
 | 
			
		||||
                email: user.email.to_string(),
 | 
			
		||||
                additional_claims: client.claims_id_token(&user),
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            OpenIDTokenResponse {
 | 
			
		||||
@@ -641,6 +643,7 @@ pub async fn user_info_post(
 | 
			
		||||
    query: web::Query<UserInfoQuery>,
 | 
			
		||||
    sessions: web::Data<Addr<OpenIDSessionsActor>>,
 | 
			
		||||
    users: web::Data<Addr<UsersActor>>,
 | 
			
		||||
    clients: web::Data<Arc<ClientManager>>,
 | 
			
		||||
) -> impl Responder {
 | 
			
		||||
    user_info(
 | 
			
		||||
        req,
 | 
			
		||||
@@ -649,6 +652,7 @@ pub async fn user_info_post(
 | 
			
		||||
            .or(query.0.access_token),
 | 
			
		||||
        sessions,
 | 
			
		||||
        users,
 | 
			
		||||
        clients,
 | 
			
		||||
    )
 | 
			
		||||
    .await
 | 
			
		||||
}
 | 
			
		||||
@@ -658,8 +662,18 @@ pub async fn user_info_get(
 | 
			
		||||
    query: web::Query<UserInfoQuery>,
 | 
			
		||||
    sessions: web::Data<Addr<OpenIDSessionsActor>>,
 | 
			
		||||
    users: web::Data<Addr<UsersActor>>,
 | 
			
		||||
    clients: web::Data<Arc<ClientManager>>,
 | 
			
		||||
) -> impl Responder {
 | 
			
		||||
    user_info(req, query.0.access_token, sessions, users).await
 | 
			
		||||
    user_info(req, query.0.access_token, sessions, users, clients).await
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(serde::Serialize)]
 | 
			
		||||
pub struct UserInfoWithCustomClaims {
 | 
			
		||||
    #[serde(flatten)]
 | 
			
		||||
    info: OpenIDUserInfo,
 | 
			
		||||
    #[serde(skip_serializing_if = "Option::is_none")]
 | 
			
		||||
    #[serde(flatten)]
 | 
			
		||||
    additional_claims: Option<AdditionalClaims>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Authenticate request using RFC6750 <https://datatracker.ietf.org/doc/html/rfc6750>///
 | 
			
		||||
@@ -668,6 +682,7 @@ async fn user_info(
 | 
			
		||||
    token: Option<String>,
 | 
			
		||||
    sessions: web::Data<Addr<OpenIDSessionsActor>>,
 | 
			
		||||
    users: web::Data<Addr<UsersActor>>,
 | 
			
		||||
    clients: web::Data<Arc<ClientManager>>,
 | 
			
		||||
) -> impl Responder {
 | 
			
		||||
    let token = match token {
 | 
			
		||||
        Some(t) => t,
 | 
			
		||||
@@ -711,6 +726,10 @@ async fn user_info(
 | 
			
		||||
        return user_info_error("invalid_request", "Access token has expired!");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let client = clients
 | 
			
		||||
        .find_by_id(&session.client)
 | 
			
		||||
        .expect("Could not extract client information!");
 | 
			
		||||
 | 
			
		||||
    let user: Option<User> = users
 | 
			
		||||
        .send(users_actor::GetUserRequest(session.user))
 | 
			
		||||
        .await
 | 
			
		||||
@@ -723,13 +742,16 @@ async fn user_info(
 | 
			
		||||
        Some(u) => u,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    HttpResponse::Ok().json(OpenIDUserInfo {
 | 
			
		||||
        name: Some(user.full_name()),
 | 
			
		||||
        sub: user.uid.0,
 | 
			
		||||
        given_name: Some(user.first_name),
 | 
			
		||||
        family_name: Some(user.last_name),
 | 
			
		||||
        preferred_username: Some(user.username),
 | 
			
		||||
        email: Some(user.email),
 | 
			
		||||
        email_verified: Some(true),
 | 
			
		||||
    HttpResponse::Ok().json(UserInfoWithCustomClaims {
 | 
			
		||||
        info: OpenIDUserInfo {
 | 
			
		||||
            name: Some(user.full_name()),
 | 
			
		||||
            sub: user.uid.0.to_string(),
 | 
			
		||||
            given_name: Some(user.first_name.to_string()),
 | 
			
		||||
            family_name: Some(user.last_name.to_string()),
 | 
			
		||||
            preferred_username: Some(user.username.to_string()),
 | 
			
		||||
            email: Some(user.email.to_string()),
 | 
			
		||||
            email_verified: Some(true),
 | 
			
		||||
        },
 | 
			
		||||
        additional_claims: client.claims_user_info(&user),
 | 
			
		||||
    })
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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