diff --git a/src/lib.rs b/src/lib.rs index 1a15fc7..84e8464 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -239,3 +239,7 @@ pub async fn get_wolves(db: &Pool) -> Vec { .await .unwrap_or(vec![]) } + +pub fn uid_to_dn(uid: &str) -> String { + format!("uid={},ou=users,dc=skynet,dc=ie", uid) +} diff --git a/src/main.rs b/src/main.rs index 1634a36..11427be 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,6 +3,7 @@ use skynet_ldap_backend::{ methods::{ account_new::post::{account, email}, account_update::post_update_ldap, + password_reset::{post_password_auth, post_password_reset}, }, State, }; @@ -26,6 +27,8 @@ async fn main() -> tide::Result<()> { app.at("/ldap/update").post(post_update_ldap); app.at("/ldap/new/email").post(email::submit); app.at("/ldap/new/account").post(account::submit); + app.at("/ldap/reset").post(post_password_reset); + app.at("/ldap/reset/auth").post(post_password_auth); app.listen(host_port).await?; Ok(()) diff --git a/src/methods/password_reset.rs b/src/methods/password_reset.rs index 64589a2..b41ea03 100644 --- a/src/methods/password_reset.rs +++ b/src/methods/password_reset.rs @@ -1,5 +1,6 @@ -use crate::{get_now_iso, random_string, Accounts, AccountsReset, Config, State}; +use crate::{get_now_iso, random_string, uid_to_dn, Accounts, AccountsReset, Config, State}; use chrono::{Duration, SecondsFormat, Utc}; +use ldap3::{exop::PasswordModify, LdapConn}; use lettre::{ message::{header, MultiPart, SinglePart}, transport::smtp::{authentication::Credentials, response::Response, Error}, @@ -70,6 +71,40 @@ pub async fn post_password_reset(mut req: Request) -> tide::Result { Ok(json!({"result": "success"}).into()) } +#[derive(Debug, Deserialize)] +pub struct PassResetAuth { + auth: String, + pass: String, +} + +pub async fn post_password_auth(mut req: Request) -> tide::Result { + let PassResetAuth { + auth, + pass, + } = req.body_json().await?; + + let config = &req.state().config; + let db = &req.state().db; + + if db_pending_clear_expired(db).await.is_err() { + return Ok(json!({"result": "success"}).into()); + } + + // check if auth exists + let details = match db_get_user_reset_auth(db, &auth).await { + None => { + return Ok(json!({"result": "success"}).into()); + } + Some(x) => x, + }; + + if ldap_reset_pw(config, &details, &pass).await.is_err() { + return Ok(json!({"result": "error", "error": "ldap error"}).into()); + }; + + Ok(json!({"result": "success", "success": "Password set"}).into()) +} + async fn db_get_user(pool: &Pool, user_in: &Option, mail_in: &Option) -> Option { let user = match user_in { None => "", @@ -133,6 +168,46 @@ async fn db_get_user_reset(pool: &Pool, user: &str) -> Option, auth: &str) -> Option { + if let Ok(res) = sqlx::query_as::<_, AccountsReset>( + r#" + SELECT * + FROM accounts_reset + WHERE auth == ? + "#, + ) + .bind(auth) + .fetch_all(pool) + .await + { + if !res.is_empty() { + return Some(res[0].to_owned()); + } + } + + None +} + +async fn ldap_reset_pw(config: &Config, details: &AccountsReset, pass: &str) -> Result<(), ldap3::LdapError> { + let mut ldap = LdapConn::new(&config.ldap_host)?; + ldap.simple_bind(&config.ldap_admin, &config.ldap_admin_pw)?.success()?; + + let dn = uid_to_dn(&details.user); + + // if so then set password + let tmp = PasswordModify { + // none as we are staying on the same connection + user_id: Some(&dn), + old_pass: None, + new_pass: Some(pass), + }; + + ldap.extended(tmp)?.success()?; + ldap.unbind()?; + + Ok(()) +} + fn send_mail(config: &Config, record: &Accounts, auth: &str) -> Result { let recipient = &record.user; let mail = &record.mail;