diff options
author | Mathijs van Veluw <[email protected]> | 2024-08-27 19:37:51 +0200 |
---|---|---|
committer | GitHub <[email protected]> | 2024-08-27 19:37:51 +0200 |
commit | 978f0092937c3a62f2de4ddc487137429754d3c0 (patch) | |
tree | 836c95e8cb1084b3cc8bf782bcdd9975eff419c8 /src | |
parent | 92f1530e96449a93eb172cb6ac920bf2b1cad603 (diff) | |
download | vaultwarden-978f0092937c3a62f2de4ddc487137429754d3c0.tar.gz vaultwarden-978f0092937c3a62f2de4ddc487137429754d3c0.zip |
Allow Org Master-Pw policy enforcement (#4899)
* Allow Org Master-Pw policy enforcement
We didn't returned the master password policy for the user.
If the `Require existing members to change their passwords` check was enabled this should trigger the login to show a change password dialog.
All the master password policies are merged into one during the login response and it will contain the max values and all `true` values which are set by all the different orgs if a user is an accepted member.
Fixes #4507
Signed-off-by: BlackDex <[email protected]>
* Use .reduce instead of .fold
Signed-off-by: BlackDex <[email protected]>
---------
Signed-off-by: BlackDex <[email protected]>
Diffstat (limited to 'src')
-rw-r--r-- | src/api/identity.rs | 46 |
1 files changed, 43 insertions, 3 deletions
diff --git a/src/api/identity.rs b/src/api/identity.rs index 93ef80bc..27f3eac6 100644 --- a/src/api/identity.rs +++ b/src/api/identity.rs @@ -135,6 +135,18 @@ async fn _refresh_login(data: ConnectData, conn: &mut DbConn) -> JsonResult { Ok(Json(result)) } +#[derive(Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +struct MasterPasswordPolicy { + min_complexity: u8, + min_length: u32, + require_lower: bool, + require_upper: bool, + require_numbers: bool, + require_special: bool, + enforce_on_login: bool, +} + async fn _password_login( data: ConnectData, user_uuid: &mut Option<String>, @@ -282,6 +294,36 @@ async fn _password_login( let (access_token, expires_in) = device.refresh_tokens(&user, scope_vec); device.save(conn).await?; + // Fetch all valid Master Password Policies and merge them into one with all true's and larges numbers as one policy + let master_password_policies: Vec<MasterPasswordPolicy> = + OrgPolicy::find_accepted_and_confirmed_by_user_and_active_policy( + &user.uuid, + OrgPolicyType::MasterPassword, + conn, + ) + .await + .into_iter() + .filter_map(|p| serde_json::from_str(&p.data).ok()) + .collect(); + + let master_password_policy = if !master_password_policies.is_empty() { + let mut mpp_json = json!(master_password_policies.into_iter().reduce(|acc, policy| { + MasterPasswordPolicy { + min_complexity: acc.min_complexity.max(policy.min_complexity), + min_length: acc.min_length.max(policy.min_length), + require_lower: acc.require_lower || policy.require_lower, + require_upper: acc.require_upper || policy.require_upper, + require_numbers: acc.require_numbers || policy.require_numbers, + require_special: acc.require_special || policy.require_special, + enforce_on_login: acc.enforce_on_login || policy.enforce_on_login, + } + })); + mpp_json["object"] = json!("masterPasswordPolicy"); + mpp_json + } else { + json!({"object": "masterPasswordPolicy"}) + }; + let mut result = json!({ "access_token": access_token, "expires_in": expires_in, @@ -297,9 +339,7 @@ async fn _password_login( "KdfParallelism": user.client_kdf_parallelism, "ResetMasterPassword": false, // TODO: Same as above "ForcePasswordReset": false, - "MasterPasswordPolicy": { - "object": "masterPasswordPolicy", - }, + "MasterPasswordPolicy": master_password_policy, "scope": scope, "unofficialServer": true, |