feat: added verification for the ssh keys

Closes #15
This commit is contained in:
silver 2023-08-19 20:41:07 +01:00
parent f41e0caa74
commit 82d7ca48bb
5 changed files with 104 additions and 7 deletions

View file

@ -32,6 +32,7 @@ async fn main() -> tide::Result<()> {
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);
app.listen(host_port).await?;
Ok(())

View file

@ -426,7 +426,9 @@ pub mod username {
pub mod ssh {
use super::*;
use crate::AccountsSSH;
use ssh_key::AuthorizedKeys;
use ldap3::Mod;
use ssh_key::{AuthorizedKeys, SshSig};
use std::collections::HashSet;
use std::fs;
// this is for a legacy member who has forgotten their account password to be able to set an email.
@ -479,7 +481,7 @@ pub mod ssh {
// check if there is ane listing entry, use that auth if exists
if let Ok(result) = sqlx::query_as::<_, AccountsSSH>(
r#"
r#"
SELECT *
FROM accounts_ssh
WHERE user == ?
@ -495,7 +497,7 @@ pub mod ssh {
// not in db, generate auth and save
let auth = random_string(50);
if sqlx::query_as::<_, AccountsSSH>(
"
"
INSERT OR REPLACE INTO accounts_ssh (user, auth_code, email)
VALUES (?1, ?2, ?3)
",
@ -514,4 +516,96 @@ pub mod ssh {
// return the full thing
Ok(json!({"result": "success","success": { "auth": auth,"keys": keys }}).into())
}
#[derive(Debug, Deserialize)]
struct RequestVerify {
user: String,
auth_signed: String,
}
// echo "auth code" | ssh-keygen -Y sign -n file -f /path/to/key
pub async fn verify(mut req: Request<State>) -> tide::Result {
let RequestVerify {
user,
auth_signed,
} = req.body_json().await?;
let db = &req.state().db;
let config = &req.state().config;
let details = if let Ok(result) = sqlx::query_as::<_, AccountsSSH>(
r#"
SELECT *
FROM accounts_ssh
WHERE user == ?
"#,
)
.bind(&user)
.fetch_one(db)
.await
{
result
} else {
return Ok(json!({ "result": "error"}).into());
};
// check if <root>/<user>/.ssh/authorized_keys exists
//let root = "/skynet_old";
let root = ".";
let path = format!("{}/{}/.ssh/authorized_keys", root, user);
let sig = match SshSig::from_pem(auth_signed) {
Ok(x) => x,
Err(_) => {
return Ok(json!({ "result": "error", "error": "Incorrect signed format"}).into());
}
};
// when ye echo it adds a newline to the end of the "file", need to duplicate it here.
let msg_tmp = format!("{}\n", details.auth_code);
let msg = msg_tmp.as_bytes();
let mut valid = false;
if fs::read_to_string(&path).is_ok() {
if let Ok(x) = AuthorizedKeys::read_file(path) {
for entry in x {
let key = entry.public_key();
match key.verify("file", msg, &sig) {
Ok(_) => {
valid = true;
break;
}
Err(_) => {}
}
}
}
}
if !valid {
return Ok(json!({"result": "error", "error": "no valid key"}).into());
}
// add to ldap
let mut ldap = LdapConn::new(&config.ldap_host)?;
ldap.simple_bind(&config.ldap_admin, &config.ldap_admin_pw)?.success()?;
let mods = vec![Mod::Replace(String::from("mail"), HashSet::from([details.email]))];
let dn = format!("uid={},ou=users,dc=skynet,dc=ie", &user);
ldap.modify(&dn, mods)?.success()?;
ldap.unbind()?;
// delete from tmp
sqlx::query_as::<_, AccountsSSH>(
r#"
DELETE FROM accounts_ssh
WHERE user == ?
"#,
)
.bind(&user)
.fetch_optional(db)
.await?;
// return the full thing
Ok(json!({"result": "success", "success": "key valid"}).into())
}
}