Browse Source

fix email as 2fa for sso

pull/6495/head
Stefan Melmuk 1 week ago
parent
commit
b953411dd5
No known key found for this signature in database GPG Key ID: 817020C608FE9C09
  1. 45
      src/api/core/two_factor/email.rs
  2. 7
      src/api/identity.rs
  3. 16
      src/db/models/user.rs

45
src/api/core/two_factor/email.rs

@ -10,7 +10,7 @@ use crate::{
auth::Headers,
crypto,
db::{
models::{EventType, TwoFactor, TwoFactorType, User, UserId},
models::{DeviceId, EventType, TwoFactor, TwoFactorType, User, UserId},
DbConn,
},
error::{Error, MapResult},
@ -24,10 +24,12 @@ pub fn routes() -> Vec<Route> {
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
struct SendEmailLoginData {
#[serde(alias = "DeviceIdentifier")]
device_identifier: DeviceId,
#[serde(alias = "Email")]
email: String,
email: Option<String>,
#[serde(alias = "MasterPasswordHash")]
master_password_hash: String,
master_password_hash: Option<String>,
}
/// User is trying to login and wants to use email 2FA.
@ -36,25 +38,36 @@ struct SendEmailLoginData {
async fn send_email_login(data: Json<SendEmailLoginData>, conn: DbConn) -> EmptyResult {
let data: SendEmailLoginData = data.into_inner();
use crate::db::models::User;
// Get the user
let Some(user) = User::find_by_mail(&data.email, &conn).await else {
err!("Username or password is incorrect. Try again.")
};
if !CONFIG._enable_email_2fa() {
err!("Email 2FA is disabled")
}
// Check password
if !user.check_valid_password(&data.master_password_hash) {
err!("Username or password is incorrect. Try again.")
}
// Get the user
let user = if let Some(email) = &data.email {
let Some(master_password_hash) = &data.master_password_hash else {
err!("No password hash has been submitted.")
};
send_token(&user.uuid, &conn).await?;
let Some(user) = User::find_by_mail(email, &conn).await else {
err!("Username or password is incorrect. Try again.")
};
Ok(())
// Check password
if !user.check_valid_password(master_password_hash) {
err!("Username or password is incorrect. Try again.")
}
user
} else {
// SSO login only sends device id, so we get the user by the most recently used device
let Some(user) = User::find_by_device(&data.device_identifier, &conn).await else {
err!("Username or password is incorrect. Try again.")
};
user
};
send_token(&user.uuid, &conn).await
}
/// Generate the token, save the data for later verification and send email to user

7
src/api/identity.rs

@ -267,6 +267,10 @@ async fn _sso_login(
}
Some((mut user, sso_user)) => {
let mut device = get_device(&data, conn, &user).await?;
// Save to update `device.updated_at` to track usage and toggle new status
device.save(conn).await?;
let twofactor_token = twofactor_auth(&mut user, &data, &mut device, ip, client_version, conn).await?;
if user.private_key.is_none() {
@ -431,6 +435,9 @@ async fn _password_login(
let mut device = get_device(&data, conn, &user).await?;
// Save to update `device.updated_at` to track usage and toggle new status
device.save(conn).await?;
let twofactor_token = twofactor_auth(&mut user, &data, &mut device, ip, client_version, conn).await?;
let auth_tokens = auth::AuthTokens::new(&device, &user, AuthMethod::Password, data.client_id);

16
src/db/models/user.rs

@ -1,4 +1,4 @@
use crate::db::schema::{invitations, sso_users, users};
use crate::db::schema::{devices, invitations, sso_users, users};
use chrono::{NaiveDateTime, TimeDelta, Utc};
use derive_more::{AsRef, Deref, Display, From};
use diesel::prelude::*;
@ -10,7 +10,7 @@ use super::{
use crate::{
api::EmptyResult,
crypto,
db::DbConn,
db::{models::DeviceId, DbConn},
error::MapResult,
sso::OIDCIdentifier,
util::{format_date, get_uuid, retry},
@ -386,6 +386,18 @@ impl User {
}}
}
pub async fn find_by_device(device_uuid: &DeviceId, conn: &DbConn) -> Option<Self> {
db_run! { conn: {
users::table
.inner_join(devices::table.on(devices::user_uuid.eq(users::uuid)))
.filter(devices::uuid.eq(device_uuid))
.select(users::all_columns)
.order_by(devices::updated_at.desc())
.first::<Self>(conn)
.ok()
}}
}
pub async fn get_all(conn: &DbConn) -> Vec<(Self, Option<SsoUser>)> {
db_run! { conn: {
users::table

Loading…
Cancel
Save