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 email_verified: Option<bool>,
|
||||||
pub preferred_username: Option<String>,
|
pub preferred_username: Option<String>,
|
||||||
pub name: 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 groups: Vec<String>,
|
||||||
pub picture: Option<String>,
|
pub picture: Option<String>,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1641,6 +1641,8 @@ impl AuthApplicationService {
|
|||||||
email: user_info.email.or(claims.email),
|
email: user_info.email.or(claims.email),
|
||||||
preferred_username: user_info.preferred_username.or(claims.preferred_username),
|
preferred_username: user_info.preferred_username.or(claims.preferred_username),
|
||||||
name: user_info.name.or(claims.name),
|
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),
|
email_verified: user_info.email_verified.or(claims.email_verified),
|
||||||
groups: if user_info.groups.is_empty() {
|
groups: if user_info.groups.is_empty() {
|
||||||
claims.groups
|
claims.groups
|
||||||
@@ -1797,6 +1799,8 @@ impl AuthApplicationService {
|
|||||||
)
|
)
|
||||||
})?;
|
})?;
|
||||||
new_user.set_image(claims.picture.clone());
|
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?;
|
let created_user = self.user_storage.create_user(new_user).await?;
|
||||||
|
|
||||||
|
|||||||
@@ -65,6 +65,8 @@ struct IdTokenClaims {
|
|||||||
email_verified: Option<bool>,
|
email_verified: Option<bool>,
|
||||||
preferred_username: Option<String>,
|
preferred_username: Option<String>,
|
||||||
name: Option<String>,
|
name: Option<String>,
|
||||||
|
given_name: Option<String>,
|
||||||
|
family_name: Option<String>,
|
||||||
groups: Option<Vec<String>>,
|
groups: Option<Vec<String>>,
|
||||||
nonce: Option<String>,
|
nonce: Option<String>,
|
||||||
picture: Option<String>,
|
picture: Option<String>,
|
||||||
@@ -90,6 +92,8 @@ struct UserInfoResponse {
|
|||||||
email_verified: Option<bool>,
|
email_verified: Option<bool>,
|
||||||
preferred_username: Option<String>,
|
preferred_username: Option<String>,
|
||||||
name: Option<String>,
|
name: Option<String>,
|
||||||
|
given_name: Option<String>,
|
||||||
|
family_name: Option<String>,
|
||||||
groups: Option<Vec<String>>,
|
groups: Option<Vec<String>>,
|
||||||
picture: Option<String>,
|
picture: Option<String>,
|
||||||
}
|
}
|
||||||
@@ -461,6 +465,8 @@ impl OidcServicePort for OidcService {
|
|||||||
email_verified: claims.email_verified,
|
email_verified: claims.email_verified,
|
||||||
preferred_username: claims.preferred_username,
|
preferred_username: claims.preferred_username,
|
||||||
name: claims.name,
|
name: claims.name,
|
||||||
|
given_name: claims.given_name,
|
||||||
|
family_name: claims.family_name,
|
||||||
groups: claims.groups.unwrap_or_default(),
|
groups: claims.groups.unwrap_or_default(),
|
||||||
picture: claims.picture,
|
picture: claims.picture,
|
||||||
})
|
})
|
||||||
@@ -513,6 +519,8 @@ impl OidcServicePort for OidcService {
|
|||||||
email_verified: info.email_verified,
|
email_verified: info.email_verified,
|
||||||
preferred_username: info.preferred_username,
|
preferred_username: info.preferred_username,
|
||||||
name: info.name,
|
name: info.name,
|
||||||
|
given_name: info.given_name,
|
||||||
|
family_name: info.family_name,
|
||||||
groups: info.groups.unwrap_or_default(),
|
groups: info.groups.unwrap_or_default(),
|
||||||
picture: info.picture,
|
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
|
/// Map a `UserDto` to a `ContactDto` so OxiCloud users appear as contacts
|
||||||
/// inside the virtual system address book.
|
/// 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 {
|
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 {
|
ContactDto {
|
||||||
id: user.id.clone(),
|
id: user.id.clone(),
|
||||||
address_book_id: SYSTEM_BOOK_ID.to_string(),
|
address_book_id: SYSTEM_BOOK_ID.to_string(),
|
||||||
uid: format!("{}@oxicloud", user.id),
|
uid: format!("{}@oxicloud", user.id),
|
||||||
full_name: Some(user.username.clone()),
|
full_name: Some(full_name),
|
||||||
first_name: None,
|
first_name: user.given_name.clone(),
|
||||||
last_name: None,
|
last_name: user.family_name.clone(),
|
||||||
nickname: None,
|
nickname: None,
|
||||||
email: vec![EmailDto {
|
email: vec![EmailDto {
|
||||||
email: user.email,
|
email: user.email,
|
||||||
|
|||||||
Reference in New Issue
Block a user