feat(user): map family/given name to OIDC & cardav
This commit is contained in:
@@ -164,6 +164,13 @@ pub struct OidcIdClaims {
|
||||
pub email_verified: Option<bool>,
|
||||
pub preferred_username: Option<String>,
|
||||
pub name: Option<String>,
|
||||
/// Standard OpenID claim `given_name` (first name). Populated on the
|
||||
/// `User` row at JIT provisioning so the share-modal autocomplete and
|
||||
/// the system address book can surface real names instead of just the
|
||||
/// (often-cryptic) `preferred_username`.
|
||||
pub given_name: Option<String>,
|
||||
/// Standard OpenID claim `family_name` (last name). See `given_name`.
|
||||
pub family_name: Option<String>,
|
||||
pub groups: Vec<String>,
|
||||
pub picture: Option<String>,
|
||||
}
|
||||
|
||||
@@ -1641,6 +1641,8 @@ impl AuthApplicationService {
|
||||
email: user_info.email.or(claims.email),
|
||||
preferred_username: user_info.preferred_username.or(claims.preferred_username),
|
||||
name: user_info.name.or(claims.name),
|
||||
given_name: user_info.given_name.or(claims.given_name),
|
||||
family_name: user_info.family_name.or(claims.family_name),
|
||||
email_verified: user_info.email_verified.or(claims.email_verified),
|
||||
groups: if user_info.groups.is_empty() {
|
||||
claims.groups
|
||||
@@ -1797,6 +1799,8 @@ impl AuthApplicationService {
|
||||
)
|
||||
})?;
|
||||
new_user.set_image(claims.picture.clone());
|
||||
new_user.set_given_name(claims.given_name.clone());
|
||||
new_user.set_family_name(claims.family_name.clone());
|
||||
|
||||
let created_user = self.user_storage.create_user(new_user).await?;
|
||||
|
||||
|
||||
@@ -65,6 +65,8 @@ struct IdTokenClaims {
|
||||
email_verified: Option<bool>,
|
||||
preferred_username: Option<String>,
|
||||
name: Option<String>,
|
||||
given_name: Option<String>,
|
||||
family_name: Option<String>,
|
||||
groups: Option<Vec<String>>,
|
||||
nonce: Option<String>,
|
||||
picture: Option<String>,
|
||||
@@ -90,6 +92,8 @@ struct UserInfoResponse {
|
||||
email_verified: Option<bool>,
|
||||
preferred_username: Option<String>,
|
||||
name: Option<String>,
|
||||
given_name: Option<String>,
|
||||
family_name: Option<String>,
|
||||
groups: Option<Vec<String>>,
|
||||
picture: Option<String>,
|
||||
}
|
||||
@@ -461,6 +465,8 @@ impl OidcServicePort for OidcService {
|
||||
email_verified: claims.email_verified,
|
||||
preferred_username: claims.preferred_username,
|
||||
name: claims.name,
|
||||
given_name: claims.given_name,
|
||||
family_name: claims.family_name,
|
||||
groups: claims.groups.unwrap_or_default(),
|
||||
picture: claims.picture,
|
||||
})
|
||||
@@ -513,6 +519,8 @@ impl OidcServicePort for OidcService {
|
||||
email_verified: info.email_verified,
|
||||
preferred_username: info.preferred_username,
|
||||
name: info.name,
|
||||
given_name: info.given_name,
|
||||
family_name: info.family_name,
|
||||
groups: info.groups.unwrap_or_default(),
|
||||
picture: info.picture,
|
||||
})
|
||||
|
||||
@@ -182,14 +182,25 @@ fn if_match_passes(if_match: Option<&str>, stored_etag: &str) -> bool {
|
||||
|
||||
/// Map a `UserDto` to a `ContactDto` so OxiCloud users appear as contacts
|
||||
/// inside the virtual system address book.
|
||||
///
|
||||
/// `given_name`/`family_name` come from OIDC standard claims at JIT
|
||||
/// provisioning (or NULL for password-only or pre-OIDC users). When
|
||||
/// they're present, prefer a "First Last" full name; otherwise fall
|
||||
/// back to the username (which is always present).
|
||||
fn user_to_contact(user: UserDto) -> ContactDto {
|
||||
let full_name = match (user.given_name.as_deref(), user.family_name.as_deref()) {
|
||||
(Some(g), Some(f)) => format!("{g} {f}"),
|
||||
(Some(g), None) => g.to_string(),
|
||||
(None, Some(f)) => f.to_string(),
|
||||
(None, None) => user.username.clone(),
|
||||
};
|
||||
ContactDto {
|
||||
id: user.id.clone(),
|
||||
address_book_id: SYSTEM_BOOK_ID.to_string(),
|
||||
uid: format!("{}@oxicloud", user.id),
|
||||
full_name: Some(user.username.clone()),
|
||||
first_name: None,
|
||||
last_name: None,
|
||||
full_name: Some(full_name),
|
||||
first_name: user.given_name.clone(),
|
||||
last_name: user.family_name.clone(),
|
||||
nickname: None,
|
||||
email: vec![EmailDto {
|
||||
email: user.email,
|
||||
|
||||
Reference in New Issue
Block a user