Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

This file was deleted.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

42 changes: 40 additions & 2 deletions crates/defguard_common/src/db/models/user.rs
Original file line number Diff line number Diff line change
Expand Up @@ -614,7 +614,7 @@ impl User<Id> {
self.totp_secret = None;

query!(
"UPDATE \"user\" SET mfa_enabled = $2, totp_enabled = $3 AND totp_secret = $4 \
"UPDATE \"user\" SET mfa_enabled = $2, totp_enabled = $3, totp_secret = $4 \
WHERE id = $1",
self.id,
self.mfa_enabled,
Expand Down Expand Up @@ -655,7 +655,7 @@ impl User<Id> {
self.email_mfa_secret = None;

query!(
"UPDATE \"user\" SET mfa_enabled = $2, email_mfa_enabled = $3 AND email_mfa_secret = $4 \
"UPDATE \"user\" SET mfa_enabled = $2, email_mfa_enabled = $3, email_mfa_secret = $4 \
WHERE id = $1",
self.id,
self.mfa_enabled,
Expand Down Expand Up @@ -1977,4 +1977,42 @@ mod test {
let settings = settings_with_ldap_password_management(false);
assert!(!user.password_management_disabled(false, &settings, false));
}

#[sqlx::test]
async fn test_disable_mfa_method_clears_its_secret(
_: PgPoolOptions,
options: PgConnectOptions,
) {
let pool = setup_pool(options).await;
let config = DefGuardConfig::new_test_config();
let _ = SERVER_CONFIG.set(config);

let mut user = User::new(
"hpotter",
Some("pass123"),
"Potter",
"Harry",
"h.potter@hogwart.edu.uk",
None,
)
.save(&pool)
.await
.unwrap();

user.new_totp_secret(&pool).await.unwrap();
user.new_email_secret(&pool).await.unwrap();
user.enable_totp(&pool).await.unwrap();
user.enable_email_mfa(&pool).await.unwrap();

user.disable_totp(&pool).await.unwrap();
user.disable_email_mfa(&pool).await.unwrap();

// Clear the secret as well as the flag so stale authenticator entries cannot re-enable
// the factor.
let stored = User::find_by_id(&pool, user.id).await.unwrap().unwrap();
assert!(!stored.totp_enabled);
assert!(!stored.email_mfa_enabled);
assert!(stored.totp_secret.is_none());
assert!(stored.email_mfa_secret.is_none());
}
}
35 changes: 24 additions & 11 deletions crates/defguard_core/src/db/models/enrollment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ use crate::mail::templates;

pub static ENROLLMENT_TOKEN_TYPE: &str = "ENROLLMENT";
pub static PASSWORD_RESET_TOKEN_TYPE: &str = "PASSWORD_RESET";
pub static MFA_CONFIG_TOKEN_TYPE: &str = "MFA_CONFIG";
// One window covers both the time to authorize and the time to configure factors.
pub const MFA_CONFIG_SESSION_TIMEOUT: Duration = Duration::from_secs(60 * 60);

#[derive(Error, Debug)]
pub enum TokenError {
Expand Down Expand Up @@ -313,18 +316,28 @@ impl Token {
transaction: &mut PgConnection,
user_id: Id,
) -> Result<(), TokenError> {
debug!("Deleting unused password reset tokens for user {user_id}");
let result = query!(
"DELETE FROM token \
WHERE user_id = $1 \
AND token_type = 'PASSWORD_RESET' \
AND used_at IS NULL",
user_id
)
.execute(transaction)
.await?;
Self::delete_unused_user_tokens_of_type(transaction, user_id, PASSWORD_RESET_TOKEN_TYPE)
.await
}

pub async fn delete_unused_user_tokens_of_type<'e, E>(
executor: E,
user_id: Id,
token_type: &str,
) -> Result<(), TokenError>
where
E: PgExecutor<'e>,
{
debug!("Deleting unused {token_type} tokens for user {user_id}");
// Plain query: the token type is a runtime parameter and needs no cached query data.
let result =
query("DELETE FROM token WHERE user_id = $1 AND token_type = $2 AND used_at IS NULL")
.bind(user_id)
.bind(token_type)
.execute(executor)
.await?;
debug!(
"Deleted {} unused password reset tokens for user {user_id}",
"Deleted {} unused {token_type} tokens for user {user_id}",
result.rows_affected()
);

Expand Down
Loading
Loading