WIP: Add bw_rs client

For some reason, we're unable to get the cookies from the reqwest result.
This commit is contained in:
ViViDboarder 2019-03-29 15:18:25 -07:00
parent 6d79984a65
commit ba1705c708
4 changed files with 172 additions and 12 deletions

View File

@ -8,3 +8,5 @@ edition = "2018"
ldap3 = "0.6" ldap3 = "0.6"
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }
toml = "0.5" toml = "0.5"
reqwest = "0.9"
serde_json = "1.0"

123
src/bw_admin.rs Normal file
View File

@ -0,0 +1,123 @@
extern crate reqwest;
extern crate serde_json;
use reqwest::Response;
use std::collections::HashMap;
use std::time::{Duration, Instant};
const COOKIE_LIFESPAN: Duration = Duration::from_secs(20 * 60);
pub struct Client {
url: String,
admin_token: String,
cookie: Option<String>,
cookie_created: Option<Instant>,
}
impl Client {
pub fn new(url: String, admin_token: String) -> Client {
Client {
url,
admin_token,
cookie: None,
cookie_created: None,
}
}
fn auth(&mut self) -> Response {
let cookie_created = Instant::now();
let result = reqwest::Client::new()
.post(format!("{}{}", &self.url, "/admin/").as_str())
.form(&[("token", &self.admin_token)])
.send()
.unwrap_or_else(|e| {
panic!("Could not authenticate with {}. {:?}", &self.url, e);
});
// TODO: Handle error statuses
println!("Auth headers: {:?}", result.headers());
if let Some(cookie) = result.headers().get(reqwest::header::SET_COOKIE) {
self.cookie = cookie.to_str().map(|s| String::from(s)).ok();
self.cookie_created = Some(cookie_created);
} else {
panic!("No cookie to set!")
}
result
}
fn ensure_auth(&mut self) {
match &self.cookie {
Some(_) => {
if self
.cookie_created
.map_or(true, |created| (created.elapsed() >= COOKIE_LIFESPAN))
{
let response = self.auth();
println!("Auth response: {:?}", response);
}
}
None => {
let response = self.auth();
println!("Auth response: {:?}", response);
}
};
// TODO: handle errors
}
fn get(&mut self, path: &str) -> Response {
self.ensure_auth();
match &self.cookie {
None => {
panic!("We haven't authenticated. Must be an error");
}
Some(cookie) => {
let url = format!("{}/admin{}", &self.url, path);
let request = reqwest::Client::new()
.get(url.as_str())
.header(reqwest::header::COOKIE, cookie.clone());
let response = request.send().unwrap_or_else(|e| {
panic!("Could not call with {}. {:?}", url, e);
});
// TODO: Handle error statuses
return response;
}
}
}
fn post(&mut self, path: &str, json: &HashMap<String, String>) -> Response {
self.ensure_auth();
match &self.cookie {
None => {
panic!("We haven't authenticated. Must be an error");
}
Some(cookie) => {
let url = format!("{}/admin{}", &self.url, path);
let request = reqwest::Client::new()
.post(url.as_str())
.header("Cookie", cookie.clone())
.json(&json);
let response = request.send().unwrap_or_else(|e| {
panic!("Could not call with {}. {:?}", url, e);
});
// TODO: Handle error statuses
return response;
}
}
}
pub fn invite(&mut self, email: &str) -> Response {
let mut json = HashMap::new();
json.insert("email".to_string(), email.to_string());
self.post("/invite", &json)
}
}

View File

@ -35,15 +35,23 @@ pub fn read_config() -> Config {
#[serde(deny_unknown_fields)] #[serde(deny_unknown_fields)]
/// Contains all config values for LDAP syncing /// Contains all config values for LDAP syncing
pub struct Config { pub struct Config {
// Bitwarden connection config
bitwarden_url: String,
bitwarden_admin_token: String,
// LDAP Connection config
ldap_host: String, ldap_host: String,
ldap_scheme: Option<String>, ldap_scheme: Option<String>,
ldap_ssl: Option<bool>, ldap_ssl: Option<bool>,
ldap_port: Option<u16>, ldap_port: Option<u16>,
// LDAP auth config
ldap_bind_dn: String, ldap_bind_dn: String,
ldap_bind_password: Pass, ldap_bind_password: Pass,
// LDAP search config
ldap_search_base_dn: String, ldap_search_base_dn: String,
ldap_search_filter: String, ldap_search_filter: String,
// LDAP record attributes
ldap_mail_field: Option<String>, ldap_mail_field: Option<String>,
// Interval syncing config
ldap_sync_interval_seconds: Option<u64>, ldap_sync_interval_seconds: Option<u64>,
} }
@ -53,6 +61,14 @@ impl Config {
read_config() read_config()
} }
pub fn get_bitwarden_url(&self) -> String {
self.bitwarden_url.clone()
}
pub fn get_bitwarden_admin_token(&self) -> String {
self.bitwarden_admin_token.clone()
}
pub fn get_ldap_url(&self) -> String { pub fn get_ldap_url(&self) -> String {
format!( format!(
"{}://{}:{}", "{}://{}:{}",

View File

@ -6,23 +6,35 @@ use std::time::Duration;
use ldap3::{DerefAliases, LdapConn, Scope, SearchEntry, SearchOptions}; use ldap3::{DerefAliases, LdapConn, Scope, SearchEntry, SearchOptions};
mod bw_admin;
mod config; mod config;
fn main() { fn main() {
let config = config::Config::from_file(); let config = config::Config::from_file();
let mut client = bw_admin::Client::new(
config.get_bitwarden_url().clone(),
config.get_bitwarden_admin_token().clone(),
);
/*
* let auth_response = client.auth();
* println!("Auth Response: {:?}", auth_response);
*/
match do_search(&config) { match do_search(&config) {
Ok(_) => (), Ok(_) => (),
Err(e) => println!("{}", e), Err(e) => println!("{}", e),
} }
if let Err(e) = invite_from_ldap(&config) { if let Err(e) = invite_from_ldap(&config, &mut client) {
println!("{}", e); println!("{}", e);
} }
if let Err(e) = start_sync_loop(&config) { /*
println!("{}", e); * if let Err(e) = start_sync_loop(&config, %mut client) {
} * println!("{}", e);
* }
*/
} }
/// Creates an LDAP connection, authenticating if necessary /// Creates an LDAP connection, authenticating if necessary
@ -80,21 +92,28 @@ fn do_search(config: &config::Config) -> Result<(), Box<Error>> {
Ok(()) Ok(())
} }
fn invite_from_ldap(config: &config::Config) -> Result<(), Box<Error>> { fn invite_from_ldap(
config: &config::Config,
client: &mut bw_admin::Client,
) -> Result<(), Box<Error>> {
let mail_field = config.get_ldap_mail_field(); let mail_field = config.get_ldap_mail_field();
for ldap_user in search_entries(config)? { for ldap_user in search_entries(config)? {
if let Some(user_email) = ldap_user.attrs[mail_field.as_str()].first() { if let Some(user_email) = ldap_user.attrs[mail_field.as_str()].first() {
println!("Try to invite user: {}", user_email); println!("Try to invite user: {}", user_email);
let response = client.invite(user_email);
println!("Invite response: {:?}", response);
} }
} }
Ok(()) Ok(())
} }
fn start_sync_loop(config: &config::Config) -> Result<(), Box<Error>> { /*
let interval = Duration::from_secs(config.get_ldap_sync_interval_seconds()); * fn start_sync_loop(config: &config::Config) -> Result<(), Box<Error>> {
loop { * let interval = Duration::from_secs(config.get_ldap_sync_interval_seconds());
invite_from_ldap(config)?; * loop {
sleep(interval); * invite_from_ldap(config)?;
} * sleep(interval);
} * }
* }
*/