feat : methods for adding and deleting ssh keys

needs testing and changes to error handling - match statements?
This commit is contained in:
daragh 2023-12-30 03:38:36 +00:00
parent 91dcb021a9
commit 0492bffe61
No known key found for this signature in database
2 changed files with 130 additions and 54 deletions

View file

@ -36,8 +36,8 @@ async fn main() -> tide::Result<()> {
//for getting current ssh keys associated with the account //for getting current ssh keys associated with the account
app.at("/ldap/ssh").post(account_ssh::get_ssh_keys); app.at("/ldap/ssh").post(account_ssh::get_ssh_keys);
//app.at("/ldap/ssh").delete(account_ssh::remove_key); app.at("/ldap/ssh").delete(account_ssh::remove_ssh_key);
//app.at("/ldap/ssh/add").post(account_ssh::add_ssh_key); app.at("/ldap/ssh/add").post(account_ssh::add_ssh_key);
app.listen(host_port).await?; app.listen(host_port).await?;
Ok(()) Ok(())

View file

@ -1,47 +1,123 @@
use crate::{methods::account_new::email::get_wolves_mail, update_group, Accounts, Config, State}; use std::collections::HashSet;
use ldap3::{exop::PasswordModify, LdapConn, LdapResult, Mod, ResultEntry, Scope, SearchEntry}; use crate::{State, LdapAuthResult, LdapAuth};
use ldap3::{LdapConn, Mod, Scope, SearchEntry};
use tide::{ use tide::{
prelude::{json, Deserialize, Serialize}, prelude::{json, Deserialize},
Request, Request,
}; };
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]
pub struct User { pub struct SSHKey {
user: String, auth: LdapAuth,
pass: String, key: String,
}
pub async fn add_ssh_key(mut req: Request<State>) -> 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<State>) -> 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<State>) -> tide::Result { pub async fn get_ssh_keys(mut req: Request<State>) -> tide::Result {
let User { let LdapAuth {
user, user,
pass pass
} = req.body_json().await?; } = req.body_json().await?;
let config = &req.state().config; let config = &req.state().config;
// easier to give each request its own connection
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); let dn = format!("uid={},ou=users,dc=skynet,dc=ie", user);
ldap.simple_bind(&dn, &pass)?.success()?; ldap.simple_bind(&dn, &pass)?.success()?;
// always assume insecure let LdapAuthResult {
let mut is_skynet_user = false; 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());
}
};
// 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<String> = vec![]; let mut keys: Vec<String> = vec![];
let (rs, _res) = ldap.search(&dn, Scope::Base, "(objectClass=*)", vec!["sshPublicKey"])?.success()?; let (rs, _res) = ldap.search(&dn, Scope::Base, "(objectClass=*)", vec!["sshPublicKey"])?.success()?;