Test / test (pull_request) Successful in 58s
A membership is a case in the built-in portal_memberships bucket: invited by a desk, a grants, the seed or the responsible pass; active from the person's first sign-in, when the provider's subject, phone number or address matches the record; removed by a desk, and invited again after that. One record per group and person however it was keyed, and at sign-in every record that matched learns what the provider verified. The active memberships join the groups claim, so Cedar sees the same parents as before. PEOPLE_BACKEND picks Kanidm or memberships; unset, a KANIDM_API_TOKEN means Kanidm. The NATS access service looks a person's groups up when a question names them by sub, phone or email and lists none. The sign-in asks for the phoneNumber scope and reads it from userinfo. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GT37Z1Xtfd9pUuQtMTg6Yt
39 lines
1.4 KiB
Rust
39 lines
1.4 KiB
Rust
use leptos::prelude::*;
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
/// The authenticated user, as established by the Kanidm OIDC flow and
|
|
/// stored in the server-side session. Ported from cnats' `auth.rs` -
|
|
/// same shape, same provider.
|
|
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
|
pub struct User {
|
|
pub sub: String,
|
|
pub username: String,
|
|
pub display_name: String,
|
|
/// Kanidm group membership, from the `groups` OIDC claim (see
|
|
/// `oauth2 update-claim-map`). Fixed at login time - not re-checked
|
|
/// live, so a group change only takes effect on the next login.
|
|
#[serde(default)]
|
|
pub groups: Vec<String>,
|
|
/// The phone number the provider verified (`phone_number`, from
|
|
/// userinfo), when it gives one: what a membership is keyed by first.
|
|
#[serde(default)]
|
|
pub phone: Option<String>,
|
|
/// The address Kanidm holds for them (the `email` claim), so a page
|
|
/// can know it is talking to the person it names as responsible.
|
|
#[serde(default)]
|
|
pub email: Option<String>,
|
|
}
|
|
|
|
pub const SESSION_USER_KEY: &str = "user";
|
|
|
|
/// Returns the currently signed-in user, if any.
|
|
#[server(endpoint = "current_user")]
|
|
pub async fn current_user() -> Result<Option<User>, ServerFnError> {
|
|
let session: tower_sessions::Session = leptos_axum::extract().await?;
|
|
let user = session
|
|
.get::<User>(SESSION_USER_KEY)
|
|
.await
|
|
.map_err(|e| ServerFnError::new(e.to_string()))?;
|
|
Ok(user)
|
|
}
|