feat: split out the auth mechanism for a user's account

Closes #25
This commit is contained in:
silver 2023-12-27 14:42:42 +00:00
parent 9924b2a2e8
commit 8f4f4b11d8
2 changed files with 121 additions and 81 deletions

View file

@ -2,7 +2,7 @@ pub mod methods;
use chrono::{Datelike, SecondsFormat, Utc};
use dotenvy::dotenv;
use ldap3::{LdapConn, Mod};
use ldap3::{exop::PasswordModify, LdapConn, Mod, Scope, SearchEntry};
use rand::{distributions::Alphanumeric, thread_rng, Rng};
use sqlx::{
sqlite::{SqliteConnectOptions, SqlitePoolOptions},
@ -321,3 +321,104 @@ pub async fn update_group(config: &Config, group: &str, users: &Vec<String>, rep
Ok(())
}
#[derive(Debug, Deserialize)]
pub struct LdapAuth {
user: String,
pass: String,
}
#[derive(Debug)]
pub struct LdapAuthResult {
ldap: LdapConn,
dn: String,
is_skynet_user: bool,
}
/// Auths and updates the users password hash
pub async fn auth_user(auth: &LdapAuth, config: &Config) -> Option<LdapAuthResult> {
let LdapAuth {
user,
pass,
} = auth;
// easier to give each request its own connection
let mut ldap = match LdapConn::new(&config.ldap_host) {
Ok(x) => x,
Err(err) => {
println!("{:?}", err);
return None;
}
};
let dn = format!("uid={},ou=users,dc=skynet,dc=ie", user);
// authenticate with the users own apssword
match ldap.simple_bind(&dn, pass) {
Ok(result) => match result.success() {
Ok(_) => {}
Err(err) => {
println!("{:?}", err);
return None;
}
},
Err(err) => {
println!("{:?}", err);
return None;
}
}
// always assume insecure
let mut pw_keep_same = false;
let mut is_skynet_user = false;
// get the users current password hash
if let Ok(result) = ldap.search(&dn, Scope::Base, "(objectClass=*)", vec!["userPassword"]) {
if let Ok((rs, _res)) = result.success() {
if !rs.is_empty() {
let tmp = SearchEntry::construct(rs[0].clone());
if tmp.attrs.contains_key("userPassword") && !tmp.attrs["userPassword"].is_empty() && tmp.attrs["userPassword"][0].starts_with("{SSHA512}") {
pw_keep_same = true;
}
if tmp.attrs.contains_key("memberOf") {
for group in tmp.attrs["memberOf"].clone() {
if group.contains("skynet-users") {
is_skynet_user = true;
}
}
}
}
}
}
if !pw_keep_same {
let tmp = PasswordModify {
// No need to set the id, since we are already authed for this
user_id: None,
old_pass: Some(pass),
// although the same as the old it will allow it to be re-hashed to SSHA512
new_pass: Some(pass),
};
match ldap.extended(tmp) {
Ok(x) => {
match x.success() {
Ok(_) => {}
Err(err) => {
println!("{:?}", err);
// not returning None as the user still managed to auth
}
}
}
Err(err) => {
println!("{:?}", err);
}
}
}
Some(LdapAuthResult {
ldap,
dn,
is_skynet_user,
})
}