|
@@ -1,19 +1,32 @@
|
|
|
|
|
+use core::fmt;
|
|
|
use std::{collections::HashSet, vec};
|
|
use std::{collections::HashSet, vec};
|
|
|
use base64::{engine::general_purpose::STANDARD, Engine as _};
|
|
use base64::{engine::general_purpose::STANDARD, Engine as _};
|
|
|
use deadpool::managed::Pool;
|
|
use deadpool::managed::Pool;
|
|
|
use ldap3::SearchEntry;
|
|
use ldap3::SearchEntry;
|
|
|
use regex::Regex;
|
|
use regex::Regex;
|
|
|
use ring::rand::{self, SecureRandom};
|
|
use ring::rand::{self, SecureRandom};
|
|
|
|
|
+use serde::Serialize;
|
|
|
use sha2::{Sha512, Digest};
|
|
use sha2::{Sha512, Digest};
|
|
|
|
|
|
|
|
pub mod pool;
|
|
pub mod pool;
|
|
|
|
|
|
|
|
use pool::{get_ldap_pool, LdapConfig, LdapManager};
|
|
use pool::{get_ldap_pool, LdapConfig, LdapManager};
|
|
|
|
|
|
|
|
|
|
+# [derive(Serialize)]
|
|
|
pub enum Error {
|
|
pub enum Error {
|
|
|
- Authfailed(String),
|
|
|
|
|
- LdapServerError(String),
|
|
|
|
|
|
|
+ Authfailed {message: String},
|
|
|
|
|
+ LdapServerError {message: String},
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+impl fmt::Display for Error {
|
|
|
|
|
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
|
+ match self {
|
|
|
|
|
+ Error::Authfailed { message } => write!(f, "{}", message),
|
|
|
|
|
+ Error::LdapServerError { message } => write!(f, "LDAP server error: {}", message),
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
#[derive(Clone)]
|
|
#[derive(Clone)]
|
|
|
pub struct LdapWrapper {
|
|
pub struct LdapWrapper {
|
|
|
ldap_pool: Pool<LdapManager>,
|
|
ldap_pool: Pool<LdapManager>,
|
|
@@ -35,12 +48,13 @@ impl LdapWrapper {
|
|
|
async fn get_user_infos(&self, uid: &String) -> Result<(bool, Vec<String>), Error> {
|
|
async fn get_user_infos(&self, uid: &String) -> Result<(bool, Vec<String>), Error> {
|
|
|
let mut ldap = self.ldap_pool.get().await.unwrap();
|
|
let mut ldap = self.ldap_pool.get().await.unwrap();
|
|
|
let search_res = ldap.search(&self.config.basedn, ldap3::Scope::Subtree, format!("(uid={})", uid).as_str(), vec!["memberOf", "objectClass"])
|
|
let search_res = ldap.search(&self.config.basedn, ldap3::Scope::Subtree, format!("(uid={})", uid).as_str(), vec!["memberOf", "objectClass"])
|
|
|
- .await.map_err(|e| {Error::LdapServerError(format!("Error: {}", e))})?;
|
|
|
|
|
|
|
+ .await.map_err(|e| {Error::LdapServerError {message: format!("Error: {}", e)}})?;
|
|
|
|
|
|
|
|
- let (result_entry, _ldap_res) = search_res.success().map_err(|e| {Error::LdapServerError(format!("Error: {}", e))})?;
|
|
|
|
|
|
|
+ let (result_entry, _ldap_res) = search_res.success()
|
|
|
|
|
+ .map_err(|e| {Error::LdapServerError {message: format!("Error: {}", e)}})?;
|
|
|
|
|
|
|
|
if result_entry.is_empty() {
|
|
if result_entry.is_empty() {
|
|
|
- return Err(Error::LdapServerError(format!("Error contact admins: dn shouldn't be empty")));
|
|
|
|
|
|
|
+ return Err(Error::LdapServerError {message: format!("Error contact admins: dn shouldn't be empty")});
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
let records = SearchEntry::construct(result_entry.first().unwrap().to_owned());
|
|
let records = SearchEntry::construct(result_entry.first().unwrap().to_owned());
|
|
@@ -65,16 +79,16 @@ impl LdapWrapper {
|
|
|
let email = Regex::new(r"^[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,6}*").unwrap();
|
|
let email = Regex::new(r"^[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,6}*").unwrap();
|
|
|
if email.is_match(&username) {
|
|
if email.is_match(&username) {
|
|
|
let search_res = ldap.search(&self.config.basedn, ldap3::Scope::Subtree, format!("(mail={})", username).as_str(), vec!["uid"])
|
|
let search_res = ldap.search(&self.config.basedn, ldap3::Scope::Subtree, format!("(mail={})", username).as_str(), vec!["uid"])
|
|
|
- .await.map_err(|e| {Error::LdapServerError(format!("Error: {}", e))})?;
|
|
|
|
|
|
|
+ .await.map_err(|e| {Error::LdapServerError {message: format!("Error: {}", e)}})?;
|
|
|
|
|
|
|
|
- let (result_entry, _ldap_res) = search_res.success().map_err(|e| {Error::LdapServerError(format!("Error: {}", e))})?;
|
|
|
|
|
|
|
+ let (result_entry, _ldap_res) = search_res.success().map_err(|e| {Error::LdapServerError {message: format!("Error: {}", e)}})?;
|
|
|
|
|
|
|
|
if result_entry.is_empty() {
|
|
if result_entry.is_empty() {
|
|
|
- return Err(Error::Authfailed(format!("Wrong username or password")));
|
|
|
|
|
|
|
+ return Err(Error::Authfailed {message: format!("Wrong username or password")});
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
if result_entry.len() > 1 {
|
|
if result_entry.len() > 1 {
|
|
|
- return Err(Error::Authfailed(format!("Error contact admins")));
|
|
|
|
|
|
|
+ return Err(Error::Authfailed {message: format!("Error contact admins")});
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
let records = SearchEntry::construct(result_entry.first().unwrap().to_owned());
|
|
let records = SearchEntry::construct(result_entry.first().unwrap().to_owned());
|
|
@@ -86,16 +100,15 @@ impl LdapWrapper {
|
|
|
.simple_bind(format!("uid={},{}", uid, self.config.basedn).as_str(), &passwd)
|
|
.simple_bind(format!("uid={},{}", uid, self.config.basedn).as_str(), &passwd)
|
|
|
.await
|
|
.await
|
|
|
.map_err(|_| {
|
|
.map_err(|_| {
|
|
|
- Error::Authfailed(format!("Wrong username or password"))
|
|
|
|
|
|
|
+ Error::Authfailed {message: format!("Wrong username or password")}
|
|
|
})
|
|
})
|
|
|
.and_then(|r| {
|
|
.and_then(|r| {
|
|
|
r.success().map_err(|_| {
|
|
r.success().map_err(|_| {
|
|
|
- Error::Authfailed(format!("Wrong username or password"))
|
|
|
|
|
|
|
+ Error::Authfailed {message: format!("Wrong username or password")}
|
|
|
})
|
|
})
|
|
|
- })
|
|
|
|
|
- .and({
|
|
|
|
|
- let (is_ssh, groups) = self.get_user_infos(&uid).await?;
|
|
|
|
|
- Ok(User{uid: uid.clone(), is_ssh, groups})})
|
|
|
|
|
|
|
+ })?;
|
|
|
|
|
+ let (is_ssh, groups) = self.get_user_infos(&uid).await?;
|
|
|
|
|
+ Ok(User{uid: uid.clone(), is_ssh, groups})
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
pub async fn change_password(&self, username: String, password: String, new_password: String) -> Result<(), Error> {
|
|
pub async fn change_password(&self, username: String, password: String, new_password: String) -> Result<(), Error> {
|
|
@@ -126,12 +139,12 @@ impl LdapWrapper {
|
|
|
let _ = ldap.simple_bind(format!("uid={},{}", username, self.config.basedn).as_str(), &password)
|
|
let _ = ldap.simple_bind(format!("uid={},{}", username, self.config.basedn).as_str(), &password)
|
|
|
.await
|
|
.await
|
|
|
.map_err(|_| {
|
|
.map_err(|_| {
|
|
|
- Error::Authfailed(format!("Wrong current password"))
|
|
|
|
|
|
|
+ Error::Authfailed {message: format!("Wrong current password")}
|
|
|
}).and_then(|r| {
|
|
}).and_then(|r| {
|
|
|
r.success().map_err(|_| {
|
|
r.success().map_err(|_| {
|
|
|
- Error::Authfailed(format!("Wrong current password"))
|
|
|
|
|
|
|
+ Error::Authfailed {message: format!("Wrong current password")}
|
|
|
})
|
|
})
|
|
|
- });
|
|
|
|
|
|
|
+ })?;
|
|
|
|
|
|
|
|
let hashset= HashSet::from([b64_new_password.as_str()]);
|
|
let hashset= HashSet::from([b64_new_password.as_str()]);
|
|
|
|
|
|
|
@@ -140,13 +153,13 @@ impl LdapWrapper {
|
|
|
ldap.modify(format!("uid={},{}", username, self.config.basedn).as_str(), data)
|
|
ldap.modify(format!("uid={},{}", username, self.config.basedn).as_str(), data)
|
|
|
.await
|
|
.await
|
|
|
.map_err(|e| {
|
|
.map_err(|e| {
|
|
|
- Error::LdapServerError(format!("An error occured, contact admins: {}", e))
|
|
|
|
|
|
|
+ Error::LdapServerError {message: format!("An error occured, contact admins: {}", e)}
|
|
|
})
|
|
})
|
|
|
.and_then(|r| {
|
|
.and_then(|r| {
|
|
|
r.success().map_err(|e| {
|
|
r.success().map_err(|e| {
|
|
|
- Error::LdapServerError(format!("An error occured, contact admins: {}", e))
|
|
|
|
|
|
|
+ Error::LdapServerError {message: format!("An error occured, contact admins: {}", e)}
|
|
|
})
|
|
})
|
|
|
- })
|
|
|
|
|
- .and(Ok(()))
|
|
|
|
|
|
|
+ })?;
|
|
|
|
|
+ Ok(())
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|