From a28e58db76cc4d2489b5a920d17b7816db5f6db3 Mon Sep 17 00:00:00 2001 From: daragh Date: Sun, 24 Dec 2023 22:02:12 +0000 Subject: [PATCH 1/7] feat : added get_ssh_keys needs testing --- src/main.rs | 7 ++++- src/methods/account_ssh.rs | 61 ++++++++++++++++++++++++++++++++++++++ src/methods/mod.rs | 1 + 3 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 src/methods/account_ssh.rs diff --git a/src/main.rs b/src/main.rs index 262d918..bac9aaa 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,6 @@ use skynet_ldap_backend::{ db_init, get_config, - methods::{account_new, account_recover, account_update}, + methods::{account_new, account_recover, account_update, account_ssh}, State, }; @@ -34,6 +34,11 @@ async fn main() -> tide::Result<()> { app.at("/ldap/recover/ssh/request").post(account_recover::ssh::request); app.at("/ldap/recover/ssh/verify").post(account_recover::ssh::verify); + //for getting current ssh keys associated with the account + app.at("/ldap/ssh").post(account_ssh::get_ssh_keys); + //app.at("/ldap/ssh").delete(account_ssh::remove_key); + //app.at("/ldap/ssh/add").post(account_ssh::add_ssh_key); + app.listen(host_port).await?; Ok(()) } diff --git a/src/methods/account_ssh.rs b/src/methods/account_ssh.rs new file mode 100644 index 0000000..c115c2f --- /dev/null +++ b/src/methods/account_ssh.rs @@ -0,0 +1,61 @@ +use crate::{methods::account_new::email::get_wolves_mail, update_group, Accounts, Config, State}; +use ldap3::{exop::PasswordModify, LdapConn, LdapResult, Mod, ResultEntry, Scope, SearchEntry}; +use tide::{ + prelude::{json, Deserialize, Serialize}, + Request, +}; + +#[derive(Debug, Deserialize)] +pub struct User { + user: String, + pass: String, +} + +pub async fn get_ssh_keys(mut req: Request) -> tide::Result { + let User { + user, + pass + } = 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 is_skynet_user = false; + + // get the users current password hash + let (rs, _res) = ldap.search(&dn, Scope::Base, "(objectClass=*)", vec!["userPassword", "memberOf"])?.success()?; + if !rs.is_empty() { + let tmp = SearchEntry::construct(rs[0].clone()); + if tmp.attrs.contains_key("memberOf") { + for group in tmp.attrs["memberOf"].clone() { + if group.contains("skynet-users") { + is_skynet_user = true; + } + } + } + } + if !is_skynet_user { + return Ok(json!({"result": "error", "error": "Invalid username or password"}).into()) + } + + let mut keys: Vec = vec![]; + let (rs, _res) = ldap.search(&dn, Scope::Base, "(objectClass=*)", vec!["sshPublicKey"])?.success()?; + for entry in rs { + let tmp = SearchEntry::construct(entry); + if tmp.attrs.contains_key("sshPublicKey") { + for key in tmp.attrs["sshPublicKey"].clone() { + keys.push(key); + } + } + } + ldap.unbind()?; + + Ok(json!({"result": "success", "success": keys}).into()) +} + + diff --git a/src/methods/mod.rs b/src/methods/mod.rs index 8273b7b..1662270 100644 --- a/src/methods/mod.rs +++ b/src/methods/mod.rs @@ -1,3 +1,4 @@ pub mod account_new; pub mod account_recover; pub mod account_update; +pub mod account_ssh; \ No newline at end of file From 91dcb021a92a197fccc8bdeb24925f4b1b91faf3 Mon Sep 17 00:00:00 2001 From: daragh Date: Sun, 24 Dec 2023 22:02:12 +0000 Subject: [PATCH 2/7] feat : added get_ssh_keys needs testing --- src/main.rs | 7 ++++- src/methods/account_ssh.rs | 61 ++++++++++++++++++++++++++++++++++++++ src/methods/mod.rs | 1 + 3 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 src/methods/account_ssh.rs diff --git a/src/main.rs b/src/main.rs index 262d918..bac9aaa 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,6 @@ use skynet_ldap_backend::{ db_init, get_config, - methods::{account_new, account_recover, account_update}, + methods::{account_new, account_recover, account_update, account_ssh}, State, }; @@ -34,6 +34,11 @@ async fn main() -> tide::Result<()> { app.at("/ldap/recover/ssh/request").post(account_recover::ssh::request); app.at("/ldap/recover/ssh/verify").post(account_recover::ssh::verify); + //for getting current ssh keys associated with the account + app.at("/ldap/ssh").post(account_ssh::get_ssh_keys); + //app.at("/ldap/ssh").delete(account_ssh::remove_key); + //app.at("/ldap/ssh/add").post(account_ssh::add_ssh_key); + app.listen(host_port).await?; Ok(()) } diff --git a/src/methods/account_ssh.rs b/src/methods/account_ssh.rs new file mode 100644 index 0000000..c115c2f --- /dev/null +++ b/src/methods/account_ssh.rs @@ -0,0 +1,61 @@ +use crate::{methods::account_new::email::get_wolves_mail, update_group, Accounts, Config, State}; +use ldap3::{exop::PasswordModify, LdapConn, LdapResult, Mod, ResultEntry, Scope, SearchEntry}; +use tide::{ + prelude::{json, Deserialize, Serialize}, + Request, +}; + +#[derive(Debug, Deserialize)] +pub struct User { + user: String, + pass: String, +} + +pub async fn get_ssh_keys(mut req: Request) -> tide::Result { + let User { + user, + pass + } = 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 is_skynet_user = false; + + // get the users current password hash + let (rs, _res) = ldap.search(&dn, Scope::Base, "(objectClass=*)", vec!["userPassword", "memberOf"])?.success()?; + if !rs.is_empty() { + let tmp = SearchEntry::construct(rs[0].clone()); + if tmp.attrs.contains_key("memberOf") { + for group in tmp.attrs["memberOf"].clone() { + if group.contains("skynet-users") { + is_skynet_user = true; + } + } + } + } + if !is_skynet_user { + return Ok(json!({"result": "error", "error": "Invalid username or password"}).into()) + } + + let mut keys: Vec = vec![]; + let (rs, _res) = ldap.search(&dn, Scope::Base, "(objectClass=*)", vec!["sshPublicKey"])?.success()?; + for entry in rs { + let tmp = SearchEntry::construct(entry); + if tmp.attrs.contains_key("sshPublicKey") { + for key in tmp.attrs["sshPublicKey"].clone() { + keys.push(key); + } + } + } + ldap.unbind()?; + + Ok(json!({"result": "success", "success": keys}).into()) +} + + diff --git a/src/methods/mod.rs b/src/methods/mod.rs index 8273b7b..1662270 100644 --- a/src/methods/mod.rs +++ b/src/methods/mod.rs @@ -1,3 +1,4 @@ pub mod account_new; pub mod account_recover; pub mod account_update; +pub mod account_ssh; \ No newline at end of file From 0492bffe612899a6fa08c8c198e9de9be940b34a Mon Sep 17 00:00:00 2001 From: daragh Date: Sat, 30 Dec 2023 03:38:36 +0000 Subject: [PATCH 3/7] feat : methods for adding and deleting ssh keys needs testing and changes to error handling - match statements? --- src/main.rs | 58 ++++++++--------- src/methods/account_ssh.rs | 126 +++++++++++++++++++++++++++++-------- 2 files changed, 130 insertions(+), 54 deletions(-) diff --git a/src/main.rs b/src/main.rs index bac9aaa..2d4af06 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,44 +1,44 @@ use skynet_ldap_backend::{ - db_init, get_config, - methods::{account_new, account_recover, account_update, account_ssh}, - State, + db_init, get_config, + methods::{account_new, account_recover, account_update, account_ssh}, + State, }; #[async_std::main] async fn main() -> tide::Result<()> { - let config = get_config(); - let db = db_init(&config).await?; + let config = get_config(); + let db = db_init(&config).await?; - let host_port = config.host_port.clone(); + let host_port = config.host_port.clone(); - tide::log::start(); + tide::log::start(); - let state = State { - db, - config, - }; + let state = State { + db, + config, + }; - let mut app = tide::with_state(state); + let mut app = tide::with_state(state); - // for users to update their own profile - app.at("/ldap/update").post(account_update::submit); + // for users to update their own profile + app.at("/ldap/update").post(account_update::submit); - // for new users - app.at("/ldap/new/email").post(account_new::email::submit); - app.at("/ldap/new/account").post(account_new::account::submit); + // for new users + app.at("/ldap/new/email").post(account_new::email::submit); + app.at("/ldap/new/account").post(account_new::account::submit); - // for folks who forget password/username - app.at("/ldap/recover/password").post(account_recover::password::reset); - app.at("/ldap/recover/password/auth").post(account_recover::password::auth); - app.at("/ldap/recover/username").post(account_recover::username::submit); - app.at("/ldap/recover/ssh/request").post(account_recover::ssh::request); - app.at("/ldap/recover/ssh/verify").post(account_recover::ssh::verify); + // for folks who forget password/username + app.at("/ldap/recover/password").post(account_recover::password::reset); + app.at("/ldap/recover/password/auth").post(account_recover::password::auth); + app.at("/ldap/recover/username").post(account_recover::username::submit); + app.at("/ldap/recover/ssh/request").post(account_recover::ssh::request); + app.at("/ldap/recover/ssh/verify").post(account_recover::ssh::verify); - //for getting current ssh keys associated with the account - app.at("/ldap/ssh").post(account_ssh::get_ssh_keys); - //app.at("/ldap/ssh").delete(account_ssh::remove_key); - //app.at("/ldap/ssh/add").post(account_ssh::add_ssh_key); + //for getting current ssh keys associated with the account + app.at("/ldap/ssh").post(account_ssh::get_ssh_keys); + app.at("/ldap/ssh").delete(account_ssh::remove_ssh_key); + app.at("/ldap/ssh/add").post(account_ssh::add_ssh_key); - app.listen(host_port).await?; - Ok(()) + app.listen(host_port).await?; + Ok(()) } diff --git a/src/methods/account_ssh.rs b/src/methods/account_ssh.rs index c115c2f..d3735a0 100644 --- a/src/methods/account_ssh.rs +++ b/src/methods/account_ssh.rs @@ -1,47 +1,123 @@ -use crate::{methods::account_new::email::get_wolves_mail, update_group, Accounts, Config, State}; -use ldap3::{exop::PasswordModify, LdapConn, LdapResult, Mod, ResultEntry, Scope, SearchEntry}; +use std::collections::HashSet; +use crate::{State, LdapAuthResult, LdapAuth}; +use ldap3::{LdapConn, Mod, Scope, SearchEntry}; use tide::{ - prelude::{json, Deserialize, Serialize}, + prelude::{json, Deserialize}, Request, }; #[derive(Debug, Deserialize)] -pub struct User { - user: String, - pass: String, +pub struct SSHKey { + auth: LdapAuth, + key: String, +} + +pub async fn add_ssh_key(mut req: Request) -> tide::Result { + let SSHKey { + auth, + key, + } = req.body_json().await?; + + let config = &req.state().config; + + let mut ldap = LdapConn::new(&config.ldap_host)?; + + let dn = format!("uid={},ou=users,dc=skynet,dc=ie", auth.user); + ldap.simple_bind(&dn, &auth.pass)?.success()?; + + let LdapAuthResult { + mut ldap, + dn, + is_skynet_user: _, + } = match crate::auth_user(&auth, config).await { + None => return Ok(json!({"result": "error", "error": "Failed to authenticate"}).into()), + Some(x) => x, + }; + + let mods = vec![ + Mod::Add("sshPublicKey".to_string(), HashSet::from([key])), + ]; + match ldap.modify(&dn, mods) { + Ok(_) => { + ldap.unbind()?; + Ok(json!({"result": "success"}).into()) + } + Err(e) => { + dbg!(e); + ldap.unbind()?; + Ok(json!({"result": "error", "error": "Failed to add key"}).into()) + } + } +} + +pub async fn remove_ssh_key(mut req: Request) -> tide::Result { + let SSHKey { + auth, + key, + } = req.body_json().await?; + let config = &req.state().config; + let mut ldap = LdapConn::new(&config.ldap_host)?; + let dn = format!("uid={},ou=users,dc=skynet,dc=ie", auth.user); + + match ldap.simple_bind(&dn, &auth.pass) { + Ok(_) => {} + Err(e) => { + dbg!(e); + return Ok(json!({"result": "error", "error": "Failed to bind"}).into()); + } + } + + let LdapAuthResult { + mut ldap, + dn, + is_skynet_user: _ + } = match crate::auth_user(&auth, config).await { + None => return Ok(json!({"result": "error", "error": "Failed to authenticate"}).into()), + Some(x) => x, + }; + + let mods = vec![ + Mod::Delete("sshPublicKey".to_string(), HashSet::from([key])), + ]; + + match ldap.modify(&dn, mods) { + Ok(_) => { + ldap.unbind()?; + Ok(json!({"result": "success"}).into()) + } + Err(e) => { + dbg!(e); + ldap.unbind()?; + Ok(json!({"result": "error", "error": "Failed to remove key"}).into()) + } + } } pub async fn get_ssh_keys(mut req: Request) -> tide::Result { - let User { + let LdapAuth { user, pass } = 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 is_skynet_user = false; - - // get the users current password hash - let (rs, _res) = ldap.search(&dn, Scope::Base, "(objectClass=*)", vec!["userPassword", "memberOf"])?.success()?; - if !rs.is_empty() { - let tmp = SearchEntry::construct(rs[0].clone()); - if tmp.attrs.contains_key("memberOf") { - for group in tmp.attrs["memberOf"].clone() { - if group.contains("skynet-users") { - is_skynet_user = true; - } - } + let LdapAuthResult { + mut ldap, + dn, + is_skynet_user: _, + } = match crate::auth_user(&LdapAuth { user, pass }, config).await { + None => return Ok(json!({"result": "error", "error": "Failed to authenticate"}).into()), + Some(x) => if x.is_skynet_user { + x + } else { + return Ok(json!({"result": "error", "error": "Not a skynet user"}).into()); } - } - if !is_skynet_user { - return Ok(json!({"result": "error", "error": "Invalid username or password"}).into()) - } + }; + let mut keys: Vec = vec![]; let (rs, _res) = ldap.search(&dn, Scope::Base, "(objectClass=*)", vec!["sshPublicKey"])?.success()?; From 2e0ba6e53c2eb17337d73def310deff60eba9c98 Mon Sep 17 00:00:00 2001 From: daragh Date: Sat, 30 Dec 2023 04:11:36 +0000 Subject: [PATCH 4/7] =?UTF-8?q?fmt=20:=20rustrover=20formatter=20is=20diff?= =?UTF-8?q?erent=20from=20cargo=20fmt=20=C2=AF\=5F(=E3=83=84)=5F/=C2=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main.rs | 58 +++++----- src/methods/account_ssh.rs | 211 +++++++++++++++++++------------------ src/methods/mod.rs | 4 +- 3 files changed, 138 insertions(+), 135 deletions(-) diff --git a/src/main.rs b/src/main.rs index 2d4af06..b3ffb03 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,44 +1,44 @@ use skynet_ldap_backend::{ - db_init, get_config, - methods::{account_new, account_recover, account_update, account_ssh}, - State, + db_init, get_config, + methods::{account_new, account_recover, account_ssh, account_update}, + State, }; #[async_std::main] async fn main() -> tide::Result<()> { - let config = get_config(); - let db = db_init(&config).await?; + let config = get_config(); + let db = db_init(&config).await?; - let host_port = config.host_port.clone(); + let host_port = config.host_port.clone(); - tide::log::start(); + tide::log::start(); - let state = State { - db, - config, - }; + let state = State { + db, + config, + }; - let mut app = tide::with_state(state); + let mut app = tide::with_state(state); - // for users to update their own profile - app.at("/ldap/update").post(account_update::submit); + // for users to update their own profile + app.at("/ldap/update").post(account_update::submit); - // for new users - app.at("/ldap/new/email").post(account_new::email::submit); - app.at("/ldap/new/account").post(account_new::account::submit); + // for new users + app.at("/ldap/new/email").post(account_new::email::submit); + app.at("/ldap/new/account").post(account_new::account::submit); - // for folks who forget password/username - app.at("/ldap/recover/password").post(account_recover::password::reset); - app.at("/ldap/recover/password/auth").post(account_recover::password::auth); - app.at("/ldap/recover/username").post(account_recover::username::submit); - app.at("/ldap/recover/ssh/request").post(account_recover::ssh::request); - app.at("/ldap/recover/ssh/verify").post(account_recover::ssh::verify); + // for folks who forget password/username + app.at("/ldap/recover/password").post(account_recover::password::reset); + app.at("/ldap/recover/password/auth").post(account_recover::password::auth); + app.at("/ldap/recover/username").post(account_recover::username::submit); + app.at("/ldap/recover/ssh/request").post(account_recover::ssh::request); + app.at("/ldap/recover/ssh/verify").post(account_recover::ssh::verify); - //for getting current ssh keys associated with the account - app.at("/ldap/ssh").post(account_ssh::get_ssh_keys); - app.at("/ldap/ssh").delete(account_ssh::remove_ssh_key); - app.at("/ldap/ssh/add").post(account_ssh::add_ssh_key); + //for getting current ssh keys associated with the account + app.at("/ldap/ssh").post(account_ssh::get_ssh_keys); + app.at("/ldap/ssh").delete(account_ssh::remove_ssh_key); + app.at("/ldap/ssh/add").post(account_ssh::add_ssh_key); - app.listen(host_port).await?; - Ok(()) + app.listen(host_port).await?; + Ok(()) } diff --git a/src/methods/account_ssh.rs b/src/methods/account_ssh.rs index d3735a0..e2b14e8 100644 --- a/src/methods/account_ssh.rs +++ b/src/methods/account_ssh.rs @@ -1,137 +1,140 @@ -use std::collections::HashSet; -use crate::{State, LdapAuthResult, LdapAuth}; +use crate::{LdapAuth, LdapAuthResult, State}; use ldap3::{LdapConn, Mod, Scope, SearchEntry}; +use std::collections::HashSet; use tide::{ - prelude::{json, Deserialize}, - Request, + prelude::{json, Deserialize}, + Request, }; #[derive(Debug, Deserialize)] pub struct SSHKey { - auth: LdapAuth, - key: String, + auth: LdapAuth, + key: String, } pub async fn add_ssh_key(mut req: Request) -> tide::Result { - let SSHKey { - auth, - key, - } = req.body_json().await?; + let SSHKey { + auth, + key, + } = req.body_json().await?; - let config = &req.state().config; + let config = &req.state().config; - let mut ldap = LdapConn::new(&config.ldap_host)?; + let mut ldap = LdapConn::new(&config.ldap_host)?; - let dn = format!("uid={},ou=users,dc=skynet,dc=ie", auth.user); - ldap.simple_bind(&dn, &auth.pass)?.success()?; + let dn = format!("uid={},ou=users,dc=skynet,dc=ie", auth.user); + ldap.simple_bind(&dn, &auth.pass)?.success()?; - let LdapAuthResult { - mut ldap, - dn, - is_skynet_user: _, - } = match crate::auth_user(&auth, config).await { - None => return Ok(json!({"result": "error", "error": "Failed to authenticate"}).into()), - Some(x) => x, - }; + let LdapAuthResult { + mut ldap, + dn, + is_skynet_user: _, + } = match crate::auth_user(&auth, config).await { + None => return Ok(json!({"result": "error", "error": "Failed to authenticate"}).into()), + Some(x) => x, + }; - let mods = vec![ - Mod::Add("sshPublicKey".to_string(), HashSet::from([key])), - ]; - match ldap.modify(&dn, mods) { - Ok(_) => { - ldap.unbind()?; - Ok(json!({"result": "success"}).into()) - } - Err(e) => { - dbg!(e); - ldap.unbind()?; - Ok(json!({"result": "error", "error": "Failed to add key"}).into()) - } + let mods = vec![Mod::Add("sshPublicKey".to_string(), HashSet::from([key]))]; + match ldap.modify(&dn, mods) { + Ok(_) => { + ldap.unbind()?; + Ok(json!({"result": "success"}).into()) } + Err(e) => { + dbg!(e); + ldap.unbind()?; + Ok(json!({"result": "error", "error": "Failed to add key"}).into()) + } + } } pub async fn remove_ssh_key(mut req: Request) -> tide::Result { - let SSHKey { - auth, - key, - } = req.body_json().await?; - let config = &req.state().config; - let mut ldap = LdapConn::new(&config.ldap_host)?; - let dn = format!("uid={},ou=users,dc=skynet,dc=ie", auth.user); + let SSHKey { + auth, + key, + } = req.body_json().await?; + let config = &req.state().config; + let mut ldap = LdapConn::new(&config.ldap_host)?; + let dn = format!("uid={},ou=users,dc=skynet,dc=ie", auth.user); - match ldap.simple_bind(&dn, &auth.pass) { - Ok(_) => {} - Err(e) => { - dbg!(e); - return Ok(json!({"result": "error", "error": "Failed to bind"}).into()); - } + match ldap.simple_bind(&dn, &auth.pass) { + Ok(_) => {} + Err(e) => { + dbg!(e); + return Ok(json!({"result": "error", "error": "Failed to bind"}).into()); } + } - let LdapAuthResult { - mut ldap, - dn, - is_skynet_user: _ - } = match crate::auth_user(&auth, config).await { - None => return Ok(json!({"result": "error", "error": "Failed to authenticate"}).into()), - Some(x) => x, - }; + let LdapAuthResult { + mut ldap, + dn, + is_skynet_user: _, + } = match crate::auth_user(&auth, config).await { + None => return Ok(json!({"result": "error", "error": "Failed to authenticate"}).into()), + Some(x) => x, + }; - let mods = vec![ - Mod::Delete("sshPublicKey".to_string(), HashSet::from([key])), - ]; + let mods = vec![Mod::Delete("sshPublicKey".to_string(), HashSet::from([key]))]; - match ldap.modify(&dn, mods) { - Ok(_) => { - ldap.unbind()?; - Ok(json!({"result": "success"}).into()) - } - Err(e) => { - dbg!(e); - ldap.unbind()?; - Ok(json!({"result": "error", "error": "Failed to remove key"}).into()) - } + match ldap.modify(&dn, mods) { + Ok(_) => { + ldap.unbind()?; + Ok(json!({"result": "success"}).into()) } + Err(e) => { + dbg!(e); + ldap.unbind()?; + Ok(json!({"result": "error", "error": "Failed to remove key"}).into()) + } + } } pub async fn get_ssh_keys(mut req: Request) -> tide::Result { - let LdapAuth { - user, - pass - } = req.body_json().await?; - let config = &req.state().config; + let LdapAuth { + user, + pass, + } = req.body_json().await?; + let config = &req.state().config; - let mut ldap = LdapConn::new(&config.ldap_host)?; + 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()?; + let dn = format!("uid={},ou=users,dc=skynet,dc=ie", user); + ldap.simple_bind(&dn, &pass)?.success()?; - let LdapAuthResult { - mut ldap, - dn, - is_skynet_user: _, - } = match crate::auth_user(&LdapAuth { user, pass }, config).await { - None => return Ok(json!({"result": "error", "error": "Failed to authenticate"}).into()), - Some(x) => if x.is_skynet_user { - x - } else { - return Ok(json!({"result": "error", "error": "Not a skynet user"}).into()); - } - }; - - - let mut keys: Vec = vec![]; - let (rs, _res) = ldap.search(&dn, Scope::Base, "(objectClass=*)", vec!["sshPublicKey"])?.success()?; - for entry in rs { - let tmp = SearchEntry::construct(entry); - if tmp.attrs.contains_key("sshPublicKey") { - for key in tmp.attrs["sshPublicKey"].clone() { - keys.push(key); - } - } + let LdapAuthResult { + mut ldap, + dn, + is_skynet_user: _, + } = match crate::auth_user( + &LdapAuth { + user, + pass, + }, + config, + ) + .await + { + None => return Ok(json!({"result": "error", "error": "Failed to authenticate"}).into()), + Some(x) => { + if x.is_skynet_user { + x + } else { + return Ok(json!({"result": "error", "error": "Not a skynet user"}).into()); + } } - ldap.unbind()?; + }; - Ok(json!({"result": "success", "success": keys}).into()) + let mut keys: Vec = vec![]; + let (rs, _res) = ldap.search(&dn, Scope::Base, "(objectClass=*)", vec!["sshPublicKey"])?.success()?; + for entry in rs { + let tmp = SearchEntry::construct(entry); + if tmp.attrs.contains_key("sshPublicKey") { + for key in tmp.attrs["sshPublicKey"].clone() { + keys.push(key); + } + } + } + ldap.unbind()?; + + Ok(json!({"result": "success", "success": keys}).into()) } - - diff --git a/src/methods/mod.rs b/src/methods/mod.rs index 1662270..311c6f1 100644 --- a/src/methods/mod.rs +++ b/src/methods/mod.rs @@ -1,4 +1,4 @@ pub mod account_new; pub mod account_recover; -pub mod account_update; -pub mod account_ssh; \ No newline at end of file +pub mod account_ssh; +pub mod account_update; \ No newline at end of file From 08ce4c39427ecc26c08abe84f823b8fc737a1764 Mon Sep 17 00:00:00 2001 From: daragh Date: Sat, 30 Dec 2023 13:09:13 +0000 Subject: [PATCH 5/7] fix : remove redundant code + fmt --- src/methods/account_ssh.rs | 31 ++++++++----------------------- src/methods/mod.rs | 2 +- 2 files changed, 9 insertions(+), 24 deletions(-) diff --git a/src/methods/account_ssh.rs b/src/methods/account_ssh.rs index e2b14e8..9488df3 100644 --- a/src/methods/account_ssh.rs +++ b/src/methods/account_ssh.rs @@ -1,5 +1,5 @@ use crate::{LdapAuth, LdapAuthResult, State}; -use ldap3::{LdapConn, Mod, Scope, SearchEntry}; +use ldap3::{Mod, Scope, SearchEntry}; use std::collections::HashSet; use tide::{ prelude::{json, Deserialize}, @@ -17,14 +17,8 @@ pub async fn add_ssh_key(mut req: Request) -> tide::Result { auth, key, } = req.body_json().await?; - let config = &req.state().config; - let mut ldap = LdapConn::new(&config.ldap_host)?; - - let dn = format!("uid={},ou=users,dc=skynet,dc=ie", auth.user); - ldap.simple_bind(&dn, &auth.pass)?.success()?; - let LdapAuthResult { mut ldap, dn, @@ -54,16 +48,6 @@ pub async fn remove_ssh_key(mut req: Request) -> tide::Result { key, } = req.body_json().await?; let config = &req.state().config; - let mut ldap = LdapConn::new(&config.ldap_host)?; - let dn = format!("uid={},ou=users,dc=skynet,dc=ie", auth.user); - - match ldap.simple_bind(&dn, &auth.pass) { - Ok(_) => {} - Err(e) => { - dbg!(e); - return Ok(json!({"result": "error", "error": "Failed to bind"}).into()); - } - } let LdapAuthResult { mut ldap, @@ -71,7 +55,13 @@ pub async fn remove_ssh_key(mut req: Request) -> tide::Result { is_skynet_user: _, } = match crate::auth_user(&auth, config).await { None => return Ok(json!({"result": "error", "error": "Failed to authenticate"}).into()), - Some(x) => x, + Some(x) => { + if x.is_skynet_user { + x + } else { + return Ok(json!({"result": "error", "error": "Not a skynet user"}).into()); + } + } }; let mods = vec![Mod::Delete("sshPublicKey".to_string(), HashSet::from([key]))]; @@ -96,11 +86,6 @@ pub async fn get_ssh_keys(mut req: Request) -> tide::Result { } = req.body_json().await?; let config = &req.state().config; - 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()?; - let LdapAuthResult { mut ldap, dn, diff --git a/src/methods/mod.rs b/src/methods/mod.rs index 311c6f1..0968f44 100644 --- a/src/methods/mod.rs +++ b/src/methods/mod.rs @@ -1,4 +1,4 @@ pub mod account_new; pub mod account_recover; pub mod account_ssh; -pub mod account_update; \ No newline at end of file +pub mod account_update; From 79edb50f656976ab5f5a2ed5b8ced31c9305aa6a Mon Sep 17 00:00:00 2001 From: daragh Date: Sun, 31 Dec 2023 00:17:43 +0000 Subject: [PATCH 6/7] fix : removed unused variables and made structs private --- src/methods/account_ssh.rs | 84 +++++++++++++++----------------------- 1 file changed, 34 insertions(+), 50 deletions(-) diff --git a/src/methods/account_ssh.rs b/src/methods/account_ssh.rs index 9488df3..641edde 100644 --- a/src/methods/account_ssh.rs +++ b/src/methods/account_ssh.rs @@ -7,7 +7,7 @@ use tide::{ }; #[derive(Debug, Deserialize)] -pub struct SSHKey { +struct SSHKey { auth: LdapAuth, key: String, } @@ -22,24 +22,24 @@ pub async fn add_ssh_key(mut req: Request) -> tide::Result { let LdapAuthResult { mut ldap, dn, - is_skynet_user: _, + .. } = match crate::auth_user(&auth, config).await { None => return Ok(json!({"result": "error", "error": "Failed to authenticate"}).into()), Some(x) => x, }; - let mods = vec![Mod::Add("sshPublicKey".to_string(), HashSet::from([key]))]; - match ldap.modify(&dn, mods) { - Ok(_) => { - ldap.unbind()?; - Ok(json!({"result": "success"}).into()) - } + let mods = vec![Mod::Add("sshPublicKey".to_owned(), HashSet::from([key]))]; + let result = match ldap.modify(&dn, mods) { + Ok(_) => Ok(json!({"result": "success"}).into()), Err(e) => { dbg!(e); - ldap.unbind()?; Ok(json!({"result": "error", "error": "Failed to add key"}).into()) } - } + }; + + ldap.unbind()?; + + result } pub async fn remove_ssh_key(mut req: Request) -> tide::Result { @@ -52,63 +52,46 @@ pub async fn remove_ssh_key(mut req: Request) -> tide::Result { let LdapAuthResult { mut ldap, dn, - is_skynet_user: _, + .. } = match crate::auth_user(&auth, config).await { None => return Ok(json!({"result": "error", "error": "Failed to authenticate"}).into()), - Some(x) => { - if x.is_skynet_user { - x - } else { - return Ok(json!({"result": "error", "error": "Not a skynet user"}).into()); - } + Some(x) => x, + }; + + let mods = vec![Mod::Delete("sshPublicKey".to_owned(), HashSet::from([key]))]; + + let result = match ldap.modify(&dn, mods) { + Ok(_) => Ok(json!({"result": "success"}).into()), + Err(e) => { + dbg!(e); + Ok(json!({"result": "error", "error": "Failed to add key"}).into()) } }; - let mods = vec![Mod::Delete("sshPublicKey".to_string(), HashSet::from([key]))]; + ldap.unbind()?; - match ldap.modify(&dn, mods) { - Ok(_) => { - ldap.unbind()?; - Ok(json!({"result": "success"}).into()) - } - Err(e) => { - dbg!(e); - ldap.unbind()?; - Ok(json!({"result": "error", "error": "Failed to remove key"}).into()) - } - } + result +} + +#[derive(Debug, Deserialize)] +struct SSHKeyGet { + auth: LdapAuth, } pub async fn get_ssh_keys(mut req: Request) -> tide::Result { - let LdapAuth { - user, - pass, + let SSHKeyGet { + auth, } = req.body_json().await?; let config = &req.state().config; let LdapAuthResult { mut ldap, dn, - is_skynet_user: _, - } = match crate::auth_user( - &LdapAuth { - user, - pass, - }, - config, - ) - .await - { + .. + } = match crate::auth_user(&auth, config).await { None => return Ok(json!({"result": "error", "error": "Failed to authenticate"}).into()), - Some(x) => { - if x.is_skynet_user { - x - } else { - return Ok(json!({"result": "error", "error": "Not a skynet user"}).into()); - } - } + Some(x) => x, }; - let mut keys: Vec = vec![]; let (rs, _res) = ldap.search(&dn, Scope::Base, "(objectClass=*)", vec!["sshPublicKey"])?.success()?; for entry in rs { @@ -119,6 +102,7 @@ pub async fn get_ssh_keys(mut req: Request) -> tide::Result { } } } + ldap.unbind()?; Ok(json!({"result": "success", "success": keys}).into()) From c72ade8dabc1ef9f5c3a570c84dafc10f19f0cf3 Mon Sep 17 00:00:00 2001 From: daragh Date: Sun, 31 Dec 2023 02:42:25 +0000 Subject: [PATCH 7/7] docs : documentation for new endpoints --- README.md | 65 +++++++++++++++++++++++++++++++++++++- src/methods/account_ssh.rs | 2 +- 2 files changed, 65 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 0f4762a..b7c949a 100644 --- a/README.md +++ b/README.md @@ -179,13 +179,76 @@ Errors: ```json {"result": "error", "error": "no valid key"} ``` - #### Success ```json {"result": "success", "success": "key valid"} ``` +### POST /ldap/ssh +Returns array of SSH keys associated with the Skynet account +```json +{ + "auth" : { + "user": "username", + "pass": "password" + } +} +``` +#### Errors +```json +{"result": "error", "error": "Failed to authenticate"} +``` +#### Success +```json +{"result": "success", "success": ["key1","key2","key3"]} +``` + +### DELETE /ldap/ssh +Deletes SSH key from Skynet account +```json +{ + "auth" : { + "user": "username", + "pass": "password" + }, + "key": "ssh key" +} +``` +#### Errors +```json +{"result": "error", "error": "Failed to authenticate"} +``` +```json +{"result": "error", "error": "Failed to remove key"} +``` +#### Success +```json +{"result": "success"} +``` + +### POST /ldap/ssh/add +Adds SSH key to Skynet account +```json +{ + "auth" : { + "user": "username", + "pass": "password" + }, + "key": "ssh key" +} +``` +#### Errors +```json +{"result": "error", "error": "Failed to authenticate"} +``` +```json +{"result": "error", "error": "Failed to add key"} +``` +#### Success +```json +{"result": "success"} +``` ## Responses Generic responses which is used unless otherwise specified above. diff --git a/src/methods/account_ssh.rs b/src/methods/account_ssh.rs index 641edde..1d6b8fd 100644 --- a/src/methods/account_ssh.rs +++ b/src/methods/account_ssh.rs @@ -64,7 +64,7 @@ pub async fn remove_ssh_key(mut req: Request) -> tide::Result { Ok(_) => Ok(json!({"result": "success"}).into()), Err(e) => { dbg!(e); - Ok(json!({"result": "error", "error": "Failed to add key"}).into()) + Ok(json!({"result": "error", "error": "Failed to remove key"}).into()) } };