Ensure users have a secure password to be added to groups #31
1 changed files with 69 additions and 15 deletions
|
@ -1,4 +1,3 @@
|
||||||
use dotenvy::dotenv;
|
|
||||||
use ldap3::{LdapConn, Mod};
|
use ldap3::{LdapConn, Mod};
|
||||||
use skynet_ldap_backend::{db_init, get_config, get_now_iso, read_csv, Accounts, Config};
|
use skynet_ldap_backend::{db_init, get_config, get_now_iso, read_csv, Accounts, Config};
|
||||||
use sqlx::{Pool, Sqlite};
|
use sqlx::{Pool, Sqlite};
|
||||||
|
@ -14,11 +13,12 @@ async fn main() -> tide::Result<()> {
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn update(config: &Config) -> 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
|
// 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") {
|
if let Ok(x) = env::var("USERS_LIFETIME") {
|
||||||
for user in x.split(',').collect::<Vec<&str>>() {
|
for user in x.split(',').collect::<Vec<&str>>() {
|
||||||
|
@ -32,22 +32,18 @@ async fn update(config: &Config) -> tide::Result<()> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Ok(x) = env::var("USERS_ADMIN") {
|
if let Ok(x) = env::var("USERS_ADMIN") {
|
||||||
let users = x.split(',').collect::<Vec<&str>>();
|
|
||||||
|
|
||||||
update_group(config, "skynet-admins", &users, true).await?;
|
|
||||||
// admins automatically get added as users
|
// admins automatically get added as users
|
||||||
for user in users {
|
for user in x.split(',').collect::<Vec<&str>>() {
|
||||||
|
admins_tmp.insert(user.to_string());
|
||||||
users_tmp.insert(user.to_string());
|
users_tmp.insert(user.to_string());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// read from teh env
|
// read from teh env
|
||||||
if let Ok(x) = env::var("USERS_COMMITTEE") {
|
if let Ok(x) = env::var("USERS_COMMITTEE") {
|
||||||
let users = x.split(',').collect::<Vec<&str>>();
|
|
||||||
|
|
||||||
update_group(config, "skynet-committee", &users, true).await?;
|
|
||||||
// committee automatically get added as users
|
// committee automatically get added as users
|
||||||
for user in users {
|
for user in x.split(',').collect::<Vec<&str>>() {
|
||||||
|
committee_tmp.insert(user.to_string());
|
||||||
users_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 AccountsSecure {
|
||||||
let users: Vec<&str> = users_tmp.iter().map(|s| &**s).collect();
|
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-users", &users, true).await?;
|
||||||
|
update_group(config, "skynet-admins", &admins, true).await?;
|
||||||
|
update_group(config, "skynet-committee", &committee, true).await?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -71,7 +72,7 @@ fn uid_to_dn(uid: &str) -> String {
|
||||||
format!("uid={},ou=users,dc=skynet,dc=ie", uid)
|
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<String>, replace: bool) -> tide::Result<()> {
|
||||||
if users.is_empty() {
|
if users.is_empty() {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
@ -178,3 +179,56 @@ async fn account_id_get_uid(db: &Pool<Sqlite>, id: &str) -> Option<String> {
|
||||||
Err(_) => None,
|
Err(_) => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct AccountsSecure {
|
||||||
|
users: Vec<String>,
|
||||||
|
admins: Vec<String>,
|
||||||
|
committee: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_secure(db: &Pool<Sqlite>, users: &HashSet<String>, admins: &HashSet<String>, committee: &HashSet<String>) -> 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<Sqlite>, group: &HashSet<String>, cache: &mut HashSet<String>) -> Vec<String> {
|
||||||
|
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<Sqlite>, 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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue