You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
101 lines
3.6 KiB
101 lines
3.6 KiB
use crate::db;
|
|
use crate::CONFIG;
|
|
use ldap3::{DerefAliases, LdapConn, Scope, SearchEntry, SearchOptions};
|
|
use ring::{digest, pbkdf2};
|
|
use std::collections::HashSet;
|
|
use std::convert::TryInto;
|
|
use std::error::Error;
|
|
use std::thread::sleep;
|
|
use std::time::Duration;
|
|
|
|
pub fn launch_ldap_connector() {
|
|
std::thread::spawn(move || {
|
|
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 {
|
|
if CONFIG._enable_ldap() {
|
|
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>> {
|
|
let existing_users = get_existing_users(&conn).expect("Error: Failed to get existing users from Bitwarden");
|
|
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!("Try to add user: {}", user_email);
|
|
// Add user
|
|
let mut user = db::models::User::new(user_email.to_string());
|
|
let mut password_bytes = vec![0u8; 16];
|
|
password_bytes = crate::crypto::get_random(password_bytes);
|
|
let password = std::str::from_utf8(password_bytes.as_slice()).unwrap();
|
|
user.set_password(password);
|
|
user.client_kdf_iter = 100000;
|
|
let key = &mut [0u8; digest::SHA256_OUTPUT_LEN];
|
|
pbkdf2::derive(
|
|
&digest::SHA256,
|
|
std::num::NonZeroU32::new(user.client_kdf_iter.try_into().unwrap()).unwrap(),
|
|
user.email.as_bytes(),
|
|
password.as_bytes(),
|
|
key,
|
|
);
|
|
user.akey = String::from_utf8(key.to_vec()).unwrap();
|
|
user.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);
|
|
|
|
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)
|
|
}
|
|
|