From bd18ad759e4dc9ffb5c9fe7b4156e608cbe7cdc3 Mon Sep 17 00:00:00 2001 From: Brendan Golden Date: Wed, 2 Aug 2023 14:52:58 +0100 Subject: [PATCH] fix: all users will need to havea secure/updated password to log in Closes #7 --- src/bin/update_groups.rs | 84 +++++++++++++++++++++++++++++++++------- 1 file changed, 69 insertions(+), 15 deletions(-) diff --git a/src/bin/update_groups.rs b/src/bin/update_groups.rs index 8ea1d30..2676980 100644 --- a/src/bin/update_groups.rs +++ b/src/bin/update_groups.rs @@ -1,4 +1,3 @@ -use dotenvy::dotenv; use ldap3::{LdapConn, Mod}; use skynet_ldap_backend::{db_init, get_config, get_now_iso, read_csv, Accounts, Config}; use sqlx::{Pool, Sqlite}; @@ -14,11 +13,12 @@ async fn main() -> tide::Result<()> { } async fn update(config: &Config) -> tide::Result<()> { - dotenv().ok(); + let db = db_init(config).await.unwrap(); - let mut users_tmp = HashSet::new(); // default user to ensure group is never empty - users_tmp.insert(String::from("compsoc")); + let mut users_tmp = HashSet::from([String::from("compsoc")]); + let mut admins_tmp = HashSet::from([String::from("compsoc")]); + let mut committee_tmp = HashSet::from([String::from("compsoc")]); if let Ok(x) = env::var("USERS_LIFETIME") { for user in x.split(',').collect::>() { @@ -32,22 +32,18 @@ async fn update(config: &Config) -> tide::Result<()> { } if let Ok(x) = env::var("USERS_ADMIN") { - let users = x.split(',').collect::>(); - - update_group(config, "skynet-admins", &users, true).await?; // admins automatically get added as users - for user in users { + for user in x.split(',').collect::>() { + admins_tmp.insert(user.to_string()); users_tmp.insert(user.to_string()); } } // read from teh env if let Ok(x) = env::var("USERS_COMMITTEE") { - let users = x.split(',').collect::>(); - - update_group(config, "skynet-committee", &users, true).await?; // committee automatically get added as users - for user in users { + for user in x.split(',').collect::>() { + committee_tmp.insert(user.to_string()); users_tmp.insert(user.to_string()); } } @@ -59,10 +55,15 @@ async fn update(config: &Config) -> tide::Result<()> { } } - // easier to work with Strings above but easier to work with &str below - let users: Vec<&str> = users_tmp.iter().map(|s| &**s).collect(); + let AccountsSecure { + users, + admins, + committee, + } = get_secure(&db, &users_tmp, &admins_tmp, &committee_tmp).await; update_group(config, "skynet-users", &users, true).await?; + update_group(config, "skynet-admins", &admins, true).await?; + update_group(config, "skynet-committee", &committee, true).await?; Ok(()) } @@ -71,7 +72,7 @@ fn uid_to_dn(uid: &str) -> String { format!("uid={},ou=users,dc=skynet,dc=ie", uid) } -async fn update_group(config: &Config, group: &str, users: &[&str], replace: bool) -> tide::Result<()> { +async fn update_group(config: &Config, group: &str, users: &Vec, replace: bool) -> tide::Result<()> { if users.is_empty() { return Ok(()); } @@ -178,3 +179,56 @@ async fn account_id_get_uid(db: &Pool, id: &str) -> Option { Err(_) => None, } } + +struct AccountsSecure { + users: Vec, + admins: Vec, + committee: Vec, +} + +async fn get_secure(db: &Pool, users: &HashSet, admins: &HashSet, committee: &HashSet) -> AccountsSecure { + // to avoid searching for teh same thing again. + let mut cache = HashSet::new(); + AccountsSecure { + users: get_secure_sub(db, users, &mut cache).await, + admins: get_secure_sub(db, admins, &mut cache).await, + committee: get_secure_sub(db, committee, &mut cache).await, + } +} + +async fn get_secure_sub(db: &Pool, group: &HashSet, cache: &mut HashSet) -> Vec { + let mut tmp = vec![]; + + for user in group { + // check the cache first + let mut add = false; + if cache.get(user).is_some() { + add = true; + } else if is_secure(db, user).await { + cache.insert(user.to_string()); + add = true; + } + + if add { + tmp.push(user.clone()); + } + } + + tmp +} +async fn is_secure(db: &Pool, user: &str) -> bool { + match sqlx::query_as::<_, Accounts>( + r#" + SELECT * + FROM accounts + WHERE user == ? AND secure == 1 + "#, + ) + .bind(user) + .fetch_all(db) + .await + { + Ok(res) => !res.is_empty(), + Err(_) => false, + } +}