tfa: add data for rate limiting and blocking

TfaUserData uses `#[serde(deny_unknown_fields)]`, so we add
this now, but using it will require explicitly enabling it.

If the TOTP count is high, the user should be locked out of
TOTP entirely until they use a recovery key to reset the
count.

If a user's TFA try count is too high, they should get rate
limited.

In both cases they should receive some kind of notification.

Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
This commit is contained in:
Wolfgang Bumiller 2023-04-20 16:08:00 +02:00
parent 8d968274f1
commit 50b793db8d

View File

@ -331,6 +331,15 @@ pub struct TfaUserData {
/// available for PVE, where the yubico API server configuration is part if the realm.
#[serde(skip_serializing_if = "Vec::is_empty", default)]
pub yubico: Vec<TfaEntry<String>>,
/// Once a user runs into a TOTP limit they get locked out of TOTP until they successfully use
/// a recovery key.
#[serde(skip_serializing_if = "bool_is_false", default)]
pub totp_locked: bool,
/// If a user hits too many 2nd factor failures, they get completely blocked for a while.
#[serde(skip_serializing_if = "Option::is_none", default)]
pub tfa_blocked_until: Option<i64>,
}
impl TfaUserData {
@ -924,6 +933,19 @@ pub struct TfaUserChallenges {
#[serde(skip_serializing_if = "Vec::is_empty", default)]
#[serde(deserialize_with = "filter_expired_challenge")]
webauthn_auths: Vec<WebauthnAuthChallenge>,
/// Number of consecutive TOTP failures. Too many of those will lock out a user.
#[serde(skip_serializing_if = "u32_is_zero", default)]
totp_failures: u32,
/// Number of consecutive 2nd factor failures. When the limit is reached, the user is locked
/// out for 12 hours.
#[serde(skip_serializing_if = "u32_is_zero", default)]
tfa_failures: u32,
}
fn u32_is_zero(n: &u32) -> bool {
*n == 0
}
/// Serde helper using our `FilteredVecVisitor` to filter out expired entries directly at load