Browse Source

Merge 7823ac7e0f into b30cc08562

pull/7500/merge
ManuA 1 week ago
committed by GitHub
parent
commit
ccaf26cced
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 4
      .env.template
  2. 41
      src/api/core/two_factor/webauthn.rs
  3. 3
      src/config.rs

4
.env.template

@ -609,6 +609,10 @@
## Enabling this would force the users to use a second factor to login every time. ## Enabling this would force the users to use a second factor to login every time.
## Note that the checkbox would still be present, but ignored. ## Note that the checkbox would still be present, but ignored.
# DISABLE_2FA_REMEMBER=false # DISABLE_2FA_REMEMBER=false
## Set WebAuthn 2FA user verification to preferred
## When enabled, compatible authenticators can request PIN or biometric verification.
# WEBAUTHN_2FA_USER_VERIFICATION=false
## ##
## Authenticator Settings ## Authenticator Settings
## Disable authenticator time drifted codes to be valid. ## Disable authenticator time drifted codes to be valid.

41
src/api/core/two_factor/webauthn.rs

@ -44,6 +44,18 @@ static WEBAUTHN: LazyLock<Webauthn> = LazyLock::new(|| {
webauthn.build().expect("Building Webauthn failed") webauthn.build().expect("Building Webauthn failed")
}); });
fn user_verification_policy() -> UserVerificationPolicy {
user_verification_policy_from_config(CONFIG.webauthn_2fa_user_verification())
}
fn user_verification_policy_from_config(preferred: bool) -> UserVerificationPolicy {
if preferred {
UserVerificationPolicy::Preferred
} else {
UserVerificationPolicy::Discouraged_DO_NOT_USE
}
}
pub fn routes() -> Vec<Route> { pub fn routes() -> Vec<Route> {
routes![get_webauthn, generate_webauthn_challenge, activate_webauthn, activate_webauthn_put, delete_webauthn,] routes![get_webauthn, generate_webauthn_challenge, activate_webauthn, activate_webauthn_put, delete_webauthn,]
} }
@ -150,7 +162,8 @@ async fn generate_webauthn_challenge(data: Json<PasswordOrOtpData>, headers: Hea
)?; )?;
let mut state = serde_json::to_value(&state)?; let mut state = serde_json::to_value(&state)?;
state["rs"]["policy"] = Value::String("discouraged".to_owned()); let user_verification_policy = user_verification_policy();
state["rs"]["policy"] = serde_json::to_value(&user_verification_policy)?;
state["rs"]["extensions"].as_object_mut().unwrap().clear(); state["rs"]["extensions"].as_object_mut().unwrap().clear();
let type_ = TwoFactorType::WebauthnRegisterChallenge; let type_ = TwoFactorType::WebauthnRegisterChallenge;
@ -160,7 +173,7 @@ async fn generate_webauthn_challenge(data: Json<PasswordOrOtpData>, headers: Hea
// we need to modify some of the default settings defined by `start_passkey_registration()`. // we need to modify some of the default settings defined by `start_passkey_registration()`.
challenge.public_key.extensions = None; challenge.public_key.extensions = None;
if let Some(asc) = challenge.public_key.authenticator_selection.as_mut() { if let Some(asc) = challenge.public_key.authenticator_selection.as_mut() {
asc.user_verification = UserVerificationPolicy::Discouraged_DO_NOT_USE; asc.user_verification = user_verification_policy;
} }
let mut challenge_value = serde_json::to_value(challenge.public_key)?; let mut challenge_value = serde_json::to_value(challenge.public_key)?;
@ -387,15 +400,16 @@ pub async fn generate_webauthn_login(user_id: &UserId, conn: &DbConn) -> JsonRes
// Generate a challenge based on the credentials // Generate a challenge based on the credentials
let (mut response, state) = WEBAUTHN.start_passkey_authentication(&creds)?; let (mut response, state) = WEBAUTHN.start_passkey_authentication(&creds)?;
// Modify to discourage user verification // Apply the configured user verification policy
let mut state = serde_json::to_value(&state)?; let mut state = serde_json::to_value(&state)?;
state["ast"]["policy"] = Value::String("discouraged".to_owned()); let user_verification_policy = user_verification_policy();
state["ast"]["policy"] = serde_json::to_value(&user_verification_policy)?;
// Add appid, this is only needed for U2F compatibility, so maybe it can be removed as well // Add appid, this is only needed for U2F compatibility, so maybe it can be removed as well
let app_id = format!("{}/app-id.json", CONFIG.domain()); let app_id = format!("{}/app-id.json", CONFIG.domain());
state["ast"]["appid"] = Value::String(app_id.clone()); state["ast"]["appid"] = Value::String(app_id.clone());
response.public_key.user_verification = UserVerificationPolicy::Discouraged_DO_NOT_USE; response.public_key.user_verification = user_verification_policy;
response response
.public_key .public_key
.extensions .extensions
@ -516,3 +530,20 @@ fn check_and_update_backup_eligible(
} }
Ok(false) Ok(false)
} }
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn configured_user_verification_policy() {
assert_eq!(
serde_json::to_value(user_verification_policy_from_config(false)).unwrap(),
"discouraged"
);
assert_eq!(
serde_json::to_value(user_verification_policy_from_config(true)).unwrap(),
"preferred"
);
}
}

3
src/config.rs

@ -717,6 +717,9 @@ make_config! {
/// Note that the checkbox would still be present, but ignored. /// Note that the checkbox would still be present, but ignored.
disable_2fa_remember: bool, true, def, false; disable_2fa_remember: bool, true, def, false;
/// Set WebAuthn 2FA user verification to preferred |> Discouraged avoids requesting a PIN or biometric check for standard WebAuthn 2FA. Preferred asks compatible authenticators for user verification and can improve compatibility with some security keys.
webauthn_2fa_user_verification: bool, true, def, false;
/// Disable authenticator time drifted codes to be valid |> Enabling this only allows the current TOTP code to be valid /// Disable authenticator time drifted codes to be valid |> Enabling this only allows the current TOTP code to be valid
/// TOTP codes of the previous and next 30 seconds will be invalid. /// TOTP codes of the previous and next 30 seconds will be invalid.
authenticator_disable_time_drift: bool, true, def, false; authenticator_disable_time_drift: bool, true, def, false;

Loading…
Cancel
Save