| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123 |
- use std::collections::HashSet;
- use base64::{engine::general_purpose::STANDARD, Engine as _};
- use deadpool::managed::Pool;
- use ldap3::SearchEntry;
- use regex::Regex;
- use ring::rand::{self, SecureRandom};
- use sha2::{Sha512, Digest};
- pub mod pool;
- use pool::{get_ldap_pool, LdapConfig, LdapManager};
- pub enum Error {
- Authfailed(String),
- LdapServerError(String)
- }
- #[derive(Clone)]
- pub struct LdapWrapper {
- ldap_pool: Pool<LdapManager>,
- config: LdapConfig,
- }
- pub struct User {
- pub uid: String,
- pub groups: Vec<String>,
- }
- impl LdapWrapper {
- pub fn new(config: LdapConfig) -> LdapWrapper {
- let ldap_pool = get_ldap_pool(config.clone());
- LdapWrapper{ldap_pool, config}
- }
- pub async fn auth(&self, username: String, passwd: String) -> Result<User, Error> {
- let mut ldap = self.ldap_pool.get().await.unwrap();
- let mut uid = username.clone();
- let email = Regex::new(r"^[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,6}*").unwrap();
- if email.is_match(&username) {
- let search_res = ldap.search(&self.config.basedn, ldap3::Scope::Subtree, format!("(mail={})", username).as_str(), vec!["uid"])
- .await.map_err(|_| {Error::Authfailed(format!("Wrong username or password"))})?;
- let (result_entry, _ldap_res) = search_res.success().map_err(|_| {Error::Authfailed(format!("Wrong username or password"))})?;
- if result_entry.is_empty() {
- return Err(Error::Authfailed(format!("No record found")));
- }
- if result_entry.len() > 1 {
- return Err(Error::Authfailed(format!("Multiple records found")));
- }
- let records = SearchEntry::construct(result_entry.first().unwrap().to_owned());
- uid = records.attrs.get("uid").unwrap().first().unwrap().to_owned();
- }
- ldap
- .simple_bind(format!("uid={},{}", uid, self.config.basedn).as_str(), &passwd)
- .await
- .map_err(|_| {
- Error::Authfailed(format!("Wrong username or password"))
- })
- .and_then(|r| {
- r.success().map_err(|_| {
- Error::Authfailed(format!("Wrong username or password"))
- })
- })
- .and(Ok(User{uid: uid, groups: vec!("coucou".to_string())})) //TODO: add groups
- }
- pub async fn change_password(&self, username: String, password: String, new_password: String) -> Result<(), Error> {
- let mut salt = [0u8; 4];
- let salt_generator = rand::SystemRandom::new();
- let _ = salt_generator.fill(&mut salt);
- let mut password_bytes = new_password.into_bytes();
- //adding salt to the end of the password
- salt.map(|elem| {
- password_bytes.push(elem);
- });
- //Getting sha512 sum
- let mut hasher = Sha512::new();
- hasher.update(password_bytes);
- let mut hash = hasher.finalize().as_slice().to_vec();
- //Adding salt to the end of hash
- salt.map(|elem| {
- hash.push(elem);
- });
- let b64_new_password = format!("{{SSHA512}}{}", STANDARD.encode(hash));
- let mut ldap = self.ldap_pool.get().await.unwrap();
- let _ = ldap.simple_bind(format!("uid={},{}", username, self.config.basedn).as_str(), &password)
- .await
- .map_err(|_| {
- Error::Authfailed(format!("Wrong current password"))
- }).and_then(|r| {
- r.success().map_err(|_| {
- Error::Authfailed(format!("Wrong current password"))
- })
- });
- let hashset= HashSet::from([b64_new_password.as_str()]);
- let data = vec![ldap3::Mod::Replace("userPassword", hashset)];
- ldap.modify(format!("uid={},{}", username, self.config.basedn).as_str(), data)
- .await
- .map_err(|e| {
- Error::LdapServerError(format!("An error occured, contact admins: {}", e))
- })
- .and_then(|r| {
- r.success().map_err(|e| {
- Error::LdapServerError(format!("An error occured, contact admins: {}", e))
- })
- })
- .and(Ok(()))
- }
- }
|