4 changed files with 95 additions and 8 deletions
			
			
		@ -0,0 +1,89 @@ | 
				
			|||
use crate::db; | 
				
			|||
use crate::CONFIG; | 
				
			|||
use ldap3::{DerefAliases, LdapConn, Scope, SearchEntry, SearchOptions}; | 
				
			|||
use std::collections::HashSet; | 
				
			|||
use std::error::Error; | 
				
			|||
use std::thread::sleep; | 
				
			|||
use std::time::Duration; | 
				
			|||
 | 
				
			|||
pub fn launch_ldap_connector() { | 
				
			|||
    let pool = db::init_pool(); | 
				
			|||
    let conn = db::DbConn(pool.get().expect("Couldn't connect to DB.")); | 
				
			|||
    let interval = Duration::from_secs(CONFIG.ldap_sync_interval()); | 
				
			|||
    loop { | 
				
			|||
        sync_from_ldap(&conn).expect("Couldn't sync users from LDAP."); | 
				
			|||
        sleep(interval); | 
				
			|||
    } | 
				
			|||
} | 
				
			|||
 | 
				
			|||
/// Invite all LDAP users to Bitwarden
 | 
				
			|||
fn sync_from_ldap(conn: &db::DbConn) -> Result<(), Box<Error>> { | 
				
			|||
    match get_existing_users(&conn) { | 
				
			|||
        Ok(existing_users) => { | 
				
			|||
            let mut num_users = 0; | 
				
			|||
            for ldap_user in search_entries()? { | 
				
			|||
                // Safely get first email from list of emails in field
 | 
				
			|||
                if let Some(user_email) = ldap_user.attrs.get("mail").and_then(|l| (l.first())) { | 
				
			|||
                    if existing_users.contains(user_email) { | 
				
			|||
                        println!("User with email already exists: {}", user_email); | 
				
			|||
                    } else { | 
				
			|||
                        println!("Try to add user: {}", user_email); | 
				
			|||
                        // Add user
 | 
				
			|||
                        db::models::User::new(user_email.to_string()).save(conn)?; | 
				
			|||
                        num_users = num_users + 1; | 
				
			|||
                    } | 
				
			|||
                } else { | 
				
			|||
                    println!("Warning: Email field, mail, not found on user"); | 
				
			|||
                } | 
				
			|||
            } | 
				
			|||
 | 
				
			|||
            // Maybe think about returning this value for some other use
 | 
				
			|||
            println!("Added {} user(s).", num_users); | 
				
			|||
        } | 
				
			|||
        Err(e) => { | 
				
			|||
            println!("Error: Failed to get existing users from Bitwarden"); | 
				
			|||
            return Err(e); | 
				
			|||
        } | 
				
			|||
    } | 
				
			|||
 | 
				
			|||
    Ok(()) | 
				
			|||
} | 
				
			|||
 | 
				
			|||
/// Retrieves search results from ldap
 | 
				
			|||
fn search_entries() -> Result<Vec<SearchEntry>, Box<Error>> { | 
				
			|||
    let ldap = LdapConn::new(CONFIG.ldap_host().as_str())?; | 
				
			|||
    ldap.simple_bind(CONFIG.ldap_bind_dn().as_str(), CONFIG.ldap_bind_password().as_str())?; | 
				
			|||
 | 
				
			|||
    let fields = vec!["uid", "givenname", "sn", "cn", "mail"]; | 
				
			|||
 | 
				
			|||
    // TODO: Something something error handling
 | 
				
			|||
    let (results, _res) = ldap | 
				
			|||
        .with_search_options(SearchOptions::new().deref(DerefAliases::Always)) | 
				
			|||
        .search( | 
				
			|||
            CONFIG.ldap_search_base_dn().as_str(), | 
				
			|||
            Scope::Subtree, | 
				
			|||
            CONFIG.ldap_search_filter().as_str(), | 
				
			|||
            fields, | 
				
			|||
        )? | 
				
			|||
        .success()?; | 
				
			|||
 | 
				
			|||
    // Build list of entries
 | 
				
			|||
    let mut entries = Vec::new(); | 
				
			|||
    for result in results { | 
				
			|||
        entries.push(SearchEntry::construct(result)); | 
				
			|||
    } | 
				
			|||
 | 
				
			|||
    Ok(entries) | 
				
			|||
} | 
				
			|||
 | 
				
			|||
/// Creates set of email addresses for users that already exist in Bitwarden
 | 
				
			|||
fn get_existing_users(conn: &db::DbConn) -> Result<HashSet<String>, Box<Error>> { | 
				
			|||
    let all_users = db::models::User::get_all(conn); | 
				
			|||
 | 
				
			|||
    let mut user_emails = HashSet::with_capacity(all_users.len()); | 
				
			|||
    for user in all_users { | 
				
			|||
        user_emails.insert(user.email); | 
				
			|||
    } | 
				
			|||
 | 
				
			|||
    Ok(user_emails) | 
				
			|||
} | 
				
			|||
					Loading…
					
					
				
		Reference in new issue