From beab2cb97be5d514812ce498c11f36f040c7241a Mon Sep 17 00:00:00 2001 From: Brendan Golden Date: Sun, 4 Jun 2023 19:39:01 +0100 Subject: [PATCH] feat: final step in creating a new user --- Cargo.lock | 23 ++++---- Cargo.toml | 3 + src/lib.rs | 10 ++++ src/main.rs | 3 +- src/methods/account_new.rs | 110 +++++++++++++++++++++++++++++++++++++ 5 files changed, 135 insertions(+), 14 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index dabe887..125bd14 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -78,6 +78,12 @@ dependencies = [ "version_check", ] +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + [[package]] name = "android_system_properties" version = "0.1.5" @@ -466,13 +472,13 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.24" +version = "0.4.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e3c5919066adf22df73762e50cffcde3a758f2a848b113b586d1f86728b673b" +checksum = "ec837a71355b28f6556dbd569b37b3f363091c0bd4b2e735674521b4c5fd9bc5" dependencies = [ + "android-tzdata", "iana-time-zone", "js-sys", - "num-integer", "num-traits", "serde", "time 0.1.45", @@ -1434,16 +1440,6 @@ dependencies = [ "minimal-lexical", ] -[[package]] -name = "num-integer" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" -dependencies = [ - "autocfg", - "num-traits", -] - [[package]] name = "num-traits" version = "0.2.15" @@ -1965,6 +1961,7 @@ name = "skynet_ldap_server" version = "0.1.0" dependencies = [ "async-std", + "chrono", "dotenv", "ldap3", "rand 0.8.5", diff --git a/Cargo.toml b/Cargo.toml index 69a00fe..522deb4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,3 +25,6 @@ surf = "2.3.2" # create random strings rand = "0.8.5" + +# fancy time stuff +chrono = "0.4.26" diff --git a/src/lib.rs b/src/lib.rs index b4a4ff0..5be9207 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -65,6 +65,8 @@ pub struct State { #[derive(Debug, Clone)] pub struct Config { ldap_host: String, + ldap_admin: String, + ldap_admin_pw: String, pub database: String, pub host_port: String, } @@ -75,6 +77,8 @@ pub fn get_config() -> Config { // reasonable defaults let mut config = Config { ldap_host: "".to_string(), + ldap_admin: "".to_string(), + ldap_admin_pw: "".to_string(), database: "database.db".to_string(), host_port: "127.0.0.1:8087".to_string(), }; @@ -82,6 +86,12 @@ pub fn get_config() -> Config { if let Ok(x) = env::var("LDAP_HOST") { config.ldap_host = x.trim().to_string(); } + if let Ok(x) = env::var("LDAP_ADMIN") { + config.ldap_admin = x.trim().to_string(); + } + if let Ok(x) = env::var("LDAP_ADMIN_PW") { + config.ldap_admin_pw = x.trim().to_string(); + } if let Ok(x) = env::var("DATABASE") { config.database = x.trim().to_string(); } diff --git a/src/main.rs b/src/main.rs index 8e5f91b..0bb96b8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,6 @@ use skynet_ldap_server::methods::account_update::post_update_ldap; use skynet_ldap_server::{db_init, get_config, State}; -use skynet_ldap_server::methods::account_new::post_new_account; +use skynet_ldap_server::methods::account_new::{post_new_account, post_new_account_confirmation}; #[async_std::main] async fn main() -> tide::Result<()> { @@ -21,6 +21,7 @@ async fn main() -> tide::Result<()> { app.at("/ldap/update").post(post_update_ldap); app.at("/ldap/new").post(post_new_account); + app.at("/ldap/new/verify").post(post_new_account_confirmation); app.listen(host_port).await?; Ok(()) diff --git a/src/methods/account_new.rs b/src/methods/account_new.rs index 0d43c99..1b9f539 100644 --- a/src/methods/account_new.rs +++ b/src/methods/account_new.rs @@ -158,4 +158,114 @@ fn create_random_string(length: usize) -> String { .take(length) .map(char::from) .collect() +} + +#[derive(Debug, Deserialize)] +pub struct LdapNewUserVerify { + auth_code: String, + password: String +} +pub async fn post_new_account_confirmation(mut req: Request) -> tide::Result { + let LdapNewUserVerify { + auth_code, + password + } = req.body_json().await?; + + let State { + db, + config, + .. + } = &req.state(); + + // make sure to clear out the expired ones first + db_pending_clear_expired(db).await; + + // search db for auth_code + let results = sqlx::query_as::<_, AccountsPending>( + r#" + SELECT * + FROM accounts_pending + WHERE auth_code == ? + "#, + ).bind(auth_code).fetch_all(db).await.unwrap_or(vec![]); + + if results.is_empty() { + return Ok(json!({"result": "error"}).into()); + } + + let mut ldap = LdapConn::new(&config.ldap_host)?; + + // need to bind as admin + ldap.simple_bind(&config.ldap_admin, &config.ldap_admin_pw)?.success()?; + + let AccountsPending{ user, mail, name_first, name_second, auth_code, discord, expiry } = &results[0]; + let dn = format!("uid={},ou=users,dc=skynet,dc=ie", user); + // TODO: find highrest uid number + let uid_number = "9990"; + let home_directory = format!("/home/{}", user); + let password_tmp = create_random_string(50); + let cn = format!("{} {}", name_first, name_second); + let labeled_uri = format!("ldap:///ou=groups,dc=skynet,dc=ie??sub?(&(objectclass=posixgroup)(memberuid={}))", user); + let sk_mail = format!("{}@skynet.ie", user); + let sk_created = get_sk_created(); + + // create user + ldap.add(&dn, vec![ + ("objectClass", HashSet::from(["top", "person", "posixaccount", "ldapPublicKey", "inetOrgPerson", "skPerson"])), + + // top + ("ou", HashSet::from(["users"])), + + // person + ("uid", HashSet::from([user.as_str()])), + ("cn", HashSet::from([cn.as_str()])), + + // posixaccount + ("uidNumber", HashSet::from([uid_number])), + ("gidNumber", HashSet::from(["1001"])), + ("homedirectory", HashSet::from([home_directory.as_str()])), + ("userpassword", HashSet::from([password_tmp.as_str()])), + + // inetOrgPerson + ("mail", HashSet::from([mail.as_str()])), + ("sn", HashSet::from([name_second.as_str()])), + + // skPerson + ("labeledURI", HashSet::from([labeled_uri.as_str()])), + ("skMail", HashSet::from([sk_mail.as_str()])), + // need to get this from wolves + //("skID", HashSet::from(["12345678"])), + ("skCreated", HashSet::from([sk_created.as_str()])), + ])?.success()?; + + // now to properly set teh password + let tmp = PasswordModify { + user_id: Some(&dn), + old_pass: Some(&password_tmp), + new_pass: Some(&password), + }; + ldap.extended(tmp)?.success()?; + + // done with ldap + ldap.unbind()?; + + // delete from tmp db + if let Ok(results) = sqlx::query_as::<_, AccountsPending>( + r#" + DELETE FROM accounts_pending + WHERE auth_code == ? + "#, + ).bind(&auth_code).fetch_all(pool).await { + println!("{:?}", results) + } + + // frontend tells user that initial password ahs been sent to tehm + Ok(json!({"result": "success"}).into()) +} + +fn get_sk_created() -> String { + use chrono::{Utc}; + let now = Utc::now(); + + format!("{}", now.format("%Y%m%d%H%M%SZ")) } \ No newline at end of file