diff --git a/src/lib.rs b/src/lib.rs index bf4716c..6b2e417 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,8 @@ +pub mod methods; +use dotenv::dotenv; use sqlx::sqlite::{SqliteConnectOptions, SqlitePoolOptions}; use sqlx::{Error, Pool, Sqlite}; - +use std::env; use std::str::FromStr; use std::time::{SystemTime, UNIX_EPOCH}; @@ -41,3 +43,39 @@ pub fn get_now() -> i64 { 0 } } + +#[derive(Clone)] +pub struct State { + pub db: Pool, + pub config: Config, +} + +#[derive(Debug, Clone)] +pub struct Config { + ldap_host: String, + pub database: String, + pub host_port: String, +} + +pub fn get_config() -> Config { + dotenv().ok(); + + // reasonable defaults + let mut config = Config { + ldap_host: "".to_string(), + database: "database.db".to_string(), + host_port: "127.0.0.1:8087".to_string(), + }; + + if let Ok(x) = env::var("LDAP_HOST") { + config.ldap_host = x.trim().to_string(); + } + if let Ok(x) = env::var("DATABASE") { + config.database = x.trim().to_string(); + } + if let Ok(x) = env::var("HOST_PORT") { + config.host_port = x.trim().to_string(); + } + + config +} diff --git a/src/main.rs b/src/main.rs index 6bef628..c1ed535 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,21 +1,5 @@ -use ldap3::{LdapConn, Mod, Scope, SearchEntry}; - -use ldap3::exop::PasswordModify; -use std::collections::HashSet; - -// for teh webserver -use dotenv::dotenv; -use skynet_ldap_server::db_init; -use sqlx::{Pool, Sqlite}; -use std::env; -use tide::prelude::{json, Deserialize}; -use tide::Request; - -#[derive(Clone)] -struct State { - db: Pool, - config: Config, -} +use skynet_ldap_server::methods::change_details::post_update_ldap; +use skynet_ldap_server::{db_init, get_config, State}; #[async_std::main] async fn main() -> tide::Result<()> { @@ -39,104 +23,6 @@ async fn main() -> tide::Result<()> { Ok(()) } -#[derive(Debug, Clone)] -struct Config { - ldap_host: String, - database: String, - host_port: String, -} -fn get_config() -> Config { - dotenv().ok(); - - // reasonable defaults - let mut config = Config { - ldap_host: "".to_string(), - database: "database.db".to_string(), - host_port: "127.0.0.1:8087".to_string(), - }; - - if let Ok(x) = env::var("LDAP_HOST") { - config.ldap_host = x.trim().to_string(); - } - if let Ok(x) = env::var("DATABASE") { - config.database = x.trim().to_string(); - } - if let Ok(x) = env::var("HOST_PORT") { - config.host_port = x.trim().to_string(); - } - - config -} - -#[derive(Debug, Deserialize)] -struct LdapUpdate { - user: String, - pass: String, - field: String, - value: String, -} -async fn post_update_ldap(mut req: Request) -> tide::Result { - let LdapUpdate { - user, - pass, - field, - value, - } = req.body_json().await?; - - let config = &req.state().config; - - // easier to give each request its own connection - let mut ldap = LdapConn::new(&config.ldap_host)?; - - let dn = format!("uid={},ou=users,dc=skynet,dc=ie", user); - ldap.simple_bind(&dn, &pass)?.success()?; - - // always assume insecure - let mut pw_keep_same = false; - - // get the users current password hash - let (rs, _res) = ldap.search(&dn, Scope::Base, "(objectClass=*)", vec!["userPassword"])?.success()?; - if !rs.is_empty() { - let tmp = SearchEntry::construct(rs[0].clone()); - if !tmp.attrs["userPassword"].is_empty() && tmp.attrs["userPassword"][0].starts_with("{SSHA512}") { - pw_keep_same = true; - } - } - - // check if the password field itself is being updated - let (pass_old, pass_new) = if &field != "userPassword" { - // if password is not being updated then just update the required field - let mods = vec![Mod::Replace(field, HashSet::from([value]))]; - ldap.modify(&dn, mods)?.success()?; - - // pass back the "old" and "new" passwords - (pass.clone(), pass.clone()) - } else { - // password is going to be updated, even if the old value is not starting with "{SSHA512}" - - pw_keep_same = false; - (pass.clone(), value) - }; - - if !pw_keep_same { - // really easy to update password once ye know how - - let tmp = PasswordModify { - // none as we are staying on the same connection - user_id: None, - - old_pass: Some(&pass_old), - new_pass: Some(&pass_new), - }; - - ldap.extended(tmp)?.success()?; - }; - - ldap.unbind()?; - - Ok(json!({"result": "success"}).into()) -} - /* Create new account diff --git a/src/methods/change_details.rs b/src/methods/change_details.rs new file mode 100644 index 0000000..ae10e7d --- /dev/null +++ b/src/methods/change_details.rs @@ -0,0 +1,75 @@ +use crate::State; +use ldap3::exop::PasswordModify; +use ldap3::{LdapConn, Mod, Scope, SearchEntry}; +use std::collections::HashSet; +use tide::prelude::{json, Deserialize}; +use tide::Request; + +#[derive(Debug, Deserialize)] +pub struct LdapUpdate { + user: String, + pass: String, + field: String, + value: String, +} +pub async fn post_update_ldap(mut req: Request) -> tide::Result { + let LdapUpdate { + user, + pass, + field, + value, + } = req.body_json().await?; + + let config = &req.state().config; + + // easier to give each request its own connection + let mut ldap = LdapConn::new(&config.ldap_host)?; + + let dn = format!("uid={},ou=users,dc=skynet,dc=ie", user); + ldap.simple_bind(&dn, &pass)?.success()?; + + // always assume insecure + let mut pw_keep_same = false; + + // get the users current password hash + let (rs, _res) = ldap.search(&dn, Scope::Base, "(objectClass=*)", vec!["userPassword"])?.success()?; + if !rs.is_empty() { + let tmp = SearchEntry::construct(rs[0].clone()); + if !tmp.attrs["userPassword"].is_empty() && tmp.attrs["userPassword"][0].starts_with("{SSHA512}") { + pw_keep_same = true; + } + } + + // check if the password field itself is being updated + let (pass_old, pass_new) = if &field != "userPassword" { + // if password is not being updated then just update the required field + let mods = vec![Mod::Replace(field, HashSet::from([value]))]; + ldap.modify(&dn, mods)?.success()?; + + // pass back the "old" and "new" passwords + (pass.clone(), pass.clone()) + } else { + // password is going to be updated, even if the old value is not starting with "{SSHA512}" + + pw_keep_same = false; + (pass.clone(), value) + }; + + if !pw_keep_same { + // really easy to update password once ye know how + + let tmp = PasswordModify { + // none as we are staying on the same connection + user_id: None, + + old_pass: Some(&pass_old), + new_pass: Some(&pass_new), + }; + + ldap.extended(tmp)?.success()?; + }; + + ldap.unbind()?; + + Ok(json!({"result": "success"}).into()) +} diff --git a/src/methods/mod.rs b/src/methods/mod.rs new file mode 100644 index 0000000..80edfea --- /dev/null +++ b/src/methods/mod.rs @@ -0,0 +1 @@ +pub mod change_details;