diff --git a/src/api/admin.rs b/src/api/admin.rs index ae30425388..c93233c451 100644 --- a/src/api/admin.rs +++ b/src/api/admin.rs @@ -282,7 +282,7 @@ async fn invite_user(data: Json, _token: AdminToken, mut conn: DbCon err_code!("User already exists", Status::Conflict.code) } - let mut user = User::new(data.email); + let mut user = User::new(data.email, None); async fn _generate_invite(user: &User, conn: &mut DbConn) -> EmptyResult { if CONFIG.mail_enabled() { diff --git a/src/api/core/accounts.rs b/src/api/core/accounts.rs index 0f56a3957c..69062a13b4 100644 --- a/src/api/core/accounts.rs +++ b/src/api/core/accounts.rs @@ -178,7 +178,7 @@ pub async fn _register(data: JsonUpcase, mut conn: DbConn) -> Json // because the vaultwarden admin can invite anyone, regardless // of other signup restrictions. if Invitation::take(&email, &mut conn).await || CONFIG.is_signup_allowed(&email) { - User::new(email.clone()) + User::new(email.clone(), None) } else { err!("Registration not allowed or user already exists") } diff --git a/src/api/core/emergency_access.rs b/src/api/core/emergency_access.rs index f5cc6a6e38..c85dfef8b6 100644 --- a/src/api/core/emergency_access.rs +++ b/src/api/core/emergency_access.rs @@ -204,7 +204,7 @@ async fn send_invite(data: JsonUpcase, headers: Heade invitation.save(&mut conn).await?; } - let mut user = User::new(email.clone()); + let mut user = User::new(email.clone(), None); user.save(&mut conn).await?; user } diff --git a/src/api/core/organizations.rs b/src/api/core/organizations.rs index a094072496..b69c04b0b5 100644 --- a/src/api/core/organizations.rs +++ b/src/api/core/organizations.rs @@ -921,7 +921,7 @@ async fn send_invite( invitation.save(&mut conn).await?; } - let mut user = User::new(email.clone()); + let mut user = User::new(email.clone(), None); user.save(&mut conn).await?; user } diff --git a/src/api/core/public.rs b/src/api/core/public.rs index 6e66668b41..5e185dfd2f 100644 --- a/src/api/core/public.rs +++ b/src/api/core/public.rs @@ -92,7 +92,7 @@ async fn ldap_import(data: JsonUpcase, token: PublicToken, mut co Some(user) => user, // exists in vaultwarden None => { // User does not exist yet - let mut new_user = User::new(user_data.Email.clone()); + let mut new_user = User::new(user_data.Email.clone(), None); new_user.save(&mut conn).await?; if !CONFIG.mail_enabled() { diff --git a/src/api/identity.rs b/src/api/identity.rs index 69e2a6f4cb..b2fb417a87 100644 --- a/src/api/identity.rs +++ b/src/api/identity.rs @@ -168,9 +168,9 @@ async fn _authorization_login( Some(code) => code, }; - let email = sso::exchange_code(code).await?; + let user_infos = sso::exchange_code(code).await?; - let user_data = match User::find_by_mail(email.as_str(), conn).await { + let user_data = match User::find_by_mail(user_infos.email.as_str(), conn).await { None => None, Some(user) => { let (mut device, new_device) = get_device(&data, conn, &user).await; @@ -186,7 +186,7 @@ async fn _authorization_login( let (user, mut device, new_device, twofactor_token) = match user_data { Some(data) => data, None => { - let mut user = User::new(email.clone()); + let mut user = User::new(user_infos.email, user_infos.user_name); user.verified_at = Some(now); user.save(conn).await?; diff --git a/src/db/models/user.rs b/src/db/models/user.rs index 1475d6372e..4d38388c2e 100644 --- a/src/db/models/user.rs +++ b/src/db/models/user.rs @@ -85,7 +85,7 @@ impl User { pub const CLIENT_KDF_TYPE_DEFAULT: i32 = UserKdfType::Pbkdf2 as i32; pub const CLIENT_KDF_ITER_DEFAULT: i32 = 600_000; - pub fn new(email: String) -> Self { + pub fn new(email: String, name: Option) -> Self { let now = Utc::now().naive_utc(); let email = email.to_lowercase(); @@ -97,7 +97,7 @@ impl User { verified_at: None, last_verifying_at: None, login_verify_count: 0, - name: email.clone(), + name: name.unwrap_or(email.clone()), email, akey: String::new(), email_new: None, diff --git a/src/sso.rs b/src/sso.rs index 94bf6a140d..b4627b9a83 100644 --- a/src/sso.rs +++ b/src/sso.rs @@ -89,6 +89,7 @@ struct AuthenticatedUser { pub nonce: String, pub refresh_token: String, pub email: String, + pub user_name: Option, } // DecodingKey and Validation used to read the SSO JWT token response @@ -131,14 +132,23 @@ fn prepare_decoding() -> (DecodingKey, Validation) { } } +#[derive(Clone, Debug)] +pub struct UserInformation { + pub email: String, + pub user_name: Option, +} + // During the 2FA flow we will // - retrieve the user information and then only discover he needs 2FA. // - second time we will rely on the `AC_CACHE` since the `code` has already been exchanged. // The `nonce` will ensure that the user is authorized only once. -// We return only the `email` to force calling `redeem` to obtain the `refresh_token`. -pub async fn exchange_code(code: &String) -> ApiResult { +// We return only the `UserInformation` to force calling `redeem` to obtain the `refresh_token`. +pub async fn exchange_code(code: &String) -> ApiResult { if let Some(authenticated_user) = AC_CACHE.get(code) { - return Ok(authenticated_user.email); + return Ok(UserInformation { + email: authenticated_user.email, + user_name: authenticated_user.user_name, + }); } let oidc_code = AuthorizationCode::new(code.clone()); @@ -178,15 +188,21 @@ pub async fn exchange_code(code: &String) -> ApiResult { }, }; + let user_name = user_info.preferred_username().map(|un| un.to_string()); + let authenticated_user = AuthenticatedUser { nonce: token.nonce, refresh_token, email: email.clone(), + user_name: user_name.clone(), }; AC_CACHE.insert(code.clone(), authenticated_user.clone()); - Ok(email) + Ok(UserInformation { + email, + user_name, + }) } Err(err) => err!(format!("Failed to contact token endpoint: {err}")), }