Merge branch 'main' into #4-password-reset

# Conflicts:
#	src/bin/update_groups.rs
This commit is contained in:
silver 2023-08-05 18:21:22 +01:00
commit 8f43e777f5
4 changed files with 157 additions and 63 deletions

View file

@ -1,8 +1,8 @@
use crate::State;
use ldap3::{exop::PasswordModify, LdapConn, Mod, Scope, SearchEntry};
use std::collections::HashSet;
use std::collections::{HashMap, HashSet};
use tide::{
prelude::{json, Deserialize},
prelude::{json, Deserialize, Serialize},
Request,
};
@ -14,6 +14,16 @@ pub struct LdapUpdate {
value: String,
}
#[derive(Debug, Serialize)]
pub struct ModifyResult {
mail: Option<String>,
#[serde(rename = "sshPublicKey")]
ssh_public_key: Option<String>,
cn: Option<String>,
#[serde(rename = "skDiscord")]
sk_discord: Option<String>,
}
/// Handles updating a single field with the users own password
pub async fn post_update_ldap(mut req: Request<State>) -> tide::Result {
let LdapUpdate {
@ -38,7 +48,6 @@ pub async fn post_update_ldap(mut req: Request<State>) -> tide::Result {
// always assume insecure
let mut pw_keep_same = false;
let mut pw_secure = false;
// get the users current password hash
let (rs, _res) = ldap.search(&dn, Scope::Base, "(objectClass=*)", vec!["userPassword"])?.success()?;
@ -46,52 +55,76 @@ pub async fn post_update_ldap(mut req: Request<State>) -> tide::Result {
let tmp = SearchEntry::construct(rs[0].clone());
if !tmp.attrs["userPassword"].is_empty() && tmp.attrs["userPassword"][0].starts_with("{SSHA512}") {
pw_keep_same = true;
pw_secure = true;
}
if tmp.attrs.contains_key("skSecure") && !tmp.attrs["skSecure"].is_empty() && tmp.attrs["skSecure"][0] == "1" {
pw_secure = true;
}
}
// check if the password field itself is being updated
let (pass_old, pass_new) = if &field != "userPassword" {
let pass_new = if &field != "userPassword" {
// if password is not being updated then just update the required field
let mut mods = vec![
// main value we are updating
let mods = vec![
// the value we are updating
Mod::Replace(field, HashSet::from([value])),
];
// if teh password is changing then its inherentrly secure, same if its currently an empty field
if !pw_keep_same || !pw_secure {
mods.push(Mod::Replace(String::from("skSecure"), HashSet::from([String::from("1")])));
}
ldap.modify(&dn, mods)?.success()?;
// pass back the "old" and "new" passwords
(pass.clone(), pass.clone())
// using this means we can create teh vars without them needing to be mutable
pass.clone()
} else {
// password is going to be updated, even if the old value is not starting with "{SSHA512}"
pw_keep_same = false;
(pass.clone(), value)
value
};
// changing teh password because of an explicit request or upgrading teh security.
if !pw_keep_same {
// really easy to update password once ye know how
let tmp = PasswordModify {
// none as we are staying on the same connection
user_id: None,
old_pass: Some(&pass_old),
old_pass: Some(&pass),
new_pass: Some(&pass_new),
};
ldap.extended(tmp)?.success()?;
};
let result = get_result(&mut ldap, &dn);
ldap.unbind()?;
Ok(json!({"result": "success"}).into())
Ok(json!({"result": "success", "success": result}).into())
}
fn get_result(ldap: &mut LdapConn, dn: &str) -> ModifyResult {
let mut result = ModifyResult {
mail: None,
ssh_public_key: None,
cn: None,
sk_discord: None,
};
if let Ok(temp) = ldap.search(dn, Scope::Base, "(objectClass=*)", vec!["mail", "sshPublicKey", "cn", "skDiscord"]) {
if let Ok((rs, _res)) = temp.success() {
if !rs.is_empty() {
let tmp = SearchEntry::construct(rs[0].clone());
result.mail = get_result_values(&tmp.attrs, "mail");
result.ssh_public_key = get_result_values(&tmp.attrs, "sshPublicKey");
result.cn = get_result_values(&tmp.attrs, "cn");
result.sk_discord = get_result_values(&tmp.attrs, "skDiscord");
}
}
}
result
}
fn get_result_values(attrs: &HashMap<String, Vec<String>>, field: &str) -> Option<String> {
if let Some(field) = attrs.get(field) {
if !field.is_empty() {
return Some(field[0].clone());
}
}
None
}