mirror of
https://github.com/dani-garcia/vaultwarden.wiki.git
synced 2026-10-22 23:48:09 +03:00
Fix email 2FA for SSO logins on iOS and Android (#7827)
* Allow email-only /api/two-factor/send-email-login for mobile clients Mobile clients (iOS) may call /api/two-factor/send-email-login with only the user's email and without a MasterPasswordHash or an AuthRequest. Permit email-only requests so the server will send the email 2FA token in that flow.\n\nModified: src/api/core/two_factor/email.rs Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(email-2fa): use device-identifier fallback when no password hash submitted iOS clients call /api/two-factor/send-email-login with an email and DeviceIdentifier but without masterPasswordHash or authRequestId after receiving a 2FA-required response from the token endpoint. The previous empty else-block allowed any caller to trigger a 2FA email for any account knowing only the email address. Replace the empty block with a device-identifier-based fallback: - Look up the most-recently-active device via find_by_device_for_email2fa. - Verify the device's associated user email matches the submitted email. - Log (debug) when the fallback path is exercised for operator visibility. - Reject with the original error when no device identifier is provided or when the device maps to a different account. Fixes #7568 * Check the pending 2FA login for this user and device Look up the pending 2FA login for the user and device instead of the latest one on the device, answer a failed check with the same error and IP/username log detail as a wrong password, and escape the device id in the logs. --------- Co-authored-by: Arunabha-Mukhopadhyay <dkarunabha2006@gmail.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
1 file changed
+19
-2
@@ -14,7 +14,10 @@ use crate::{
|
||||
crypto,
|
||||
db::{
|
||||
DbConn,
|
||||
models::{AuthRequest, AuthRequestId, DeviceId, EventType, TwoFactor, TwoFactorType, User, UserId},
|
||||
models::{
|
||||
AuthRequest, AuthRequestId, DeviceId, EventType, TwoFactor, TwoFactorIncomplete, TwoFactorType, User,
|
||||
UserId,
|
||||
},
|
||||
},
|
||||
error::{Error, MapResult},
|
||||
mail,
|
||||
@@ -94,6 +97,20 @@ async fn send_email_login(data: Json<SendEmailLoginData>, client_headers: Client
|
||||
{
|
||||
err!("AuthRequest doesn't exist", "Invalid device, IP or code")
|
||||
}
|
||||
} else if let Some(device_identifier) = &data.device_identifier {
|
||||
// iOS/Android SSO logins send the email and device id but no password hash,
|
||||
// so accept a device that has a pending 2FA login for this user
|
||||
if TwoFactorIncomplete::find_by_user_and_device(&user.uuid, device_identifier, &conn).await.is_none() {
|
||||
err!(
|
||||
"Username or password is incorrect. Try again",
|
||||
format!("IP: {}. Username: {}.", client_headers.ip.ip, email.escape_debug())
|
||||
)
|
||||
}
|
||||
debug!(
|
||||
"Email 2FA fallback: pending login. Username: {}. Device: {}.",
|
||||
user.email,
|
||||
device_identifier.to_string().escape_debug()
|
||||
);
|
||||
} else {
|
||||
err!("No password hash has been submitted.")
|
||||
}
|
||||
@@ -107,7 +124,7 @@ async fn send_email_login(data: Json<SendEmailLoginData>, client_headers: Client
|
||||
let Some(user) = User::find_by_device_for_email2fa(device_identifier, &conn).await else {
|
||||
err!(
|
||||
"Username or password is incorrect. Try again",
|
||||
format!("IP: {}. Device: {device_identifier}.", client_headers.ip.ip)
|
||||
format!("IP: {}. Device: {}.", client_headers.ip.ip, device_identifier.to_string().escape_debug())
|
||||
)
|
||||
};
|
||||
|
||||
|
||||
Reference in new issue
Block a user