mirror of
https://github.com/ViViDboarder/bitwarden_rs_ldap.git
synced 2024-11-21 18:56:27 +00:00
WIP: Add bw_rs client
For some reason, we're unable to get the cookies from the reqwest result.
This commit is contained in:
parent
6d79984a65
commit
ba1705c708
@ -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
123
src/bw_admin.rs
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
@ -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!(
|
||||||
"{}://{}:{}",
|
"{}://{}:{}",
|
||||||
|
43
src/main.rs
43
src/main.rs
@ -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);
|
||||||
}
|
* }
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
Loading…
Reference in New Issue
Block a user