Browse Source

Make SSO AMR customizable

Signed-off-by: Kowalski Dragon (kowalski7cc) <kowalski7cc@users.noreply.github.com>
pull/7749/head
Kowalski Dragon (kowalski7cc) 2 weeks ago
parent
commit
09d50dc5a3
No known key found for this signature in database GPG Key ID: C4E819BD2BC6233E
  1. 7
      .env.template
  2. 13
      src/api/identity.rs
  3. 14
      src/config.rs
  4. 5
      src/sso_client.rs

7
.env.template

@ -552,8 +552,11 @@
## Optional Master password policy (minComplexity=[0-4]), `enforceOnLogin` is not supported at the moment.
# SSO_MASTER_PASSWORD_POLICY='{"enforceOnLogin":false,"minComplexity":3,"minLength":12,"requireLower":false,"requireNumbers":false,"requireSpecial":false,"requireUpper":false}'
## Skip Vaultwarden 2FA for SSO: false (never), true (always), auto (only when the IdP returns an MFA ACR/AMR claim)
# SSO_SKIP_2FA=false
## Skip Vaultwarden 2FA for SSO/social login: false (never), true (always), auto (only when the IdP returns an MFA ACR/AMR claim)
# SSO_2FA_SKIP=false
## In auto mode, comma-separated OIDC AMR values that indicate MFA. Set blank to disable AMR matching.
# SSO_2FA_AMR="mfa,otp,fido2,webauthn,hwk"
## Use sso only for authentication not the session lifecycle
# SSO_AUTH_ONLY_NOT_SESSION=false

13
src/api/identity.rs

@ -37,7 +37,7 @@ use crate::{
},
error::MapResult,
mail, sso,
sso::{OIDCCode, OIDCCodeChallenge, OIDCCodeVerifier, OIDCState, SSO_2FA_ACR},
sso::{OIDCCode, OIDCCodeChallenge, OIDCCodeVerifier, OIDCState},
util,
};
@ -353,15 +353,12 @@ async fn sso_login(
Some((mut user, sso_user)) => {
let mut device = get_device(&data, conn, &user).await?;
let skip_2fa = match CONFIG.sso_skip_2fa().as_str() {
let skip_2fa = match CONFIG.sso_2fa_skip().as_str() {
"true" => true,
"auto" => {
user_infos.acr.as_deref() == Some(SSO_2FA_ACR)
|| user_infos.amr.as_ref().is_some_and(|amr| {
amr.iter().any(|method| {
matches!(method.as_str(), "mfa" | "otp" | "fido2" | "webauthn" | "hwk")
})
})
let amr_values = CONFIG.sso_2fa_amr_vec();
user_infos.acr.as_deref() == Some(crate::sso::SSO_2FA_ACR)
|| user_infos.amr.as_ref().is_some_and(|amr| amr.iter().any(|method| amr_values.contains(method)))
}
_ => false,
};

14
src/config.rs

@ -845,8 +845,10 @@ make_config! {
sso_auth_only_not_session: bool, true, def, false;
/// Client cache for discovery endpoint. |> Duration in seconds (0 or less to disable). More details: https://github.com/dani-garcia/vaultwarden/wiki/Enabling-SSO-support-using-OpenId-Connect#client-cache
sso_client_cache_expiration: u64, true, def, 0;
/// Skip 2FA for SSO login |> `false` keeps Vaultwarden 2FA, `true` always skips it, `auto` skips it only when the IdP returns the requested ACR level
sso_skip_2fa: String, true, def, "false".to_string();
/// Skip 2FA for SSO/social login |> `false` keeps Vaultwarden 2FA, `true` always skips it, `auto` skips it only when the IdP returns an MFA AMR or ACR claim
sso_2fa_skip: String, true, def, "false".to_string();
/// SSO 2FA AMR values |> Comma-separated AMR values that satisfy `SSO_2FA_SKIP=auto`
sso_2fa_amr: String, true, def, "mfa,otp,fido2,webauthn,hwk".to_string();
/// Log all tokens |> `LOG_LEVEL=debug` or `LOG_LEVEL=info,vaultwarden::sso=debug` is required
sso_debug_tokens: bool, true, def, false;
},
@ -1118,8 +1120,8 @@ fn validate_config(cfg: &ConfigItems, on_update: bool) -> Result<(), Error> {
validate_sso_master_password_policy(cfg.sso_master_password_policy.as_ref())?;
}
if !matches!(cfg.sso_skip_2fa.as_str(), "false" | "true" | "auto") {
err!("`SSO_SKIP_2FA` must be one of: false, true, auto");
if !matches!(cfg.sso_2fa_skip.as_str(), "false" | "true" | "auto") {
err!("`SSO_2FA_SKIP` must be one of: false, true, auto");
}
if cfg._enable_yubico {
@ -1710,6 +1712,10 @@ impl Config {
pub fn sso_authorize_extra_params_vec(&self) -> Vec<(String, String)> {
url::form_urlencoded::parse(self.sso_authorize_extra_params().as_bytes()).into_owned().collect()
}
pub fn sso_2fa_amr_vec(&self) -> Vec<String> {
self.sso_2fa_amr().split(',').map(str::trim).filter(|v| !v.is_empty()).map(str::to_owned).collect()
}
}
use handlebars::{

5
src/sso_client.rs

@ -202,9 +202,8 @@ impl Client {
.add_scopes(scopes)
.add_extra_params(CONFIG.sso_authorize_extra_params_vec());
if CONFIG.sso_skip_2fa() == "auto" {
auth_req = auth_req
.add_extra_param(
if CONFIG.sso_2fa_skip() == "auto" {
auth_req = auth_req.add_extra_param(
"claims",
serde_json::json!({
"id_token": {

Loading…
Cancel
Save