lib.rs 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. use std::collections::HashSet;
  2. use base64::{engine::general_purpose::STANDARD, Engine as _};
  3. use deadpool::managed::Pool;
  4. use ldap3::SearchEntry;
  5. use regex::Regex;
  6. use ring::rand::{self, SecureRandom};
  7. use sha2::{Sha512, Digest};
  8. pub mod pool;
  9. use pool::{get_ldap_pool, LdapConfig, LdapManager};
  10. pub enum Error {
  11. Authfailed(String),
  12. LdapServerError(String)
  13. }
  14. #[derive(Clone)]
  15. pub struct LdapWrapper {
  16. ldap_pool: Pool<LdapManager>,
  17. config: LdapConfig,
  18. }
  19. pub struct User {
  20. pub uid: String,
  21. pub groups: Vec<String>,
  22. }
  23. impl LdapWrapper {
  24. pub fn new(config: LdapConfig) -> LdapWrapper {
  25. let ldap_pool = get_ldap_pool(config.clone());
  26. LdapWrapper{ldap_pool, config}
  27. }
  28. pub async fn auth(&self, username: String, passwd: String) -> Result<User, Error> {
  29. let mut ldap = self.ldap_pool.get().await.unwrap();
  30. let mut uid = username.clone();
  31. let email = Regex::new(r"^[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,6}*").unwrap();
  32. if email.is_match(&username) {
  33. let search_res = ldap.search(&self.config.basedn, ldap3::Scope::Subtree, format!("(mail={})", username).as_str(), vec!["uid"])
  34. .await.map_err(|_| {Error::Authfailed(format!("Wrong username or password"))})?;
  35. let (result_entry, _ldap_res) = search_res.success().map_err(|_| {Error::Authfailed(format!("Wrong username or password"))})?;
  36. if result_entry.is_empty() {
  37. return Err(Error::Authfailed(format!("No record found")));
  38. }
  39. if result_entry.len() > 1 {
  40. return Err(Error::Authfailed(format!("Multiple records found")));
  41. }
  42. let records = SearchEntry::construct(result_entry.first().unwrap().to_owned());
  43. uid = records.attrs.get("uid").unwrap().first().unwrap().to_owned();
  44. }
  45. ldap
  46. .simple_bind(format!("uid={},{}", uid, self.config.basedn).as_str(), &passwd)
  47. .await
  48. .map_err(|_| {
  49. Error::Authfailed(format!("Wrong username or password"))
  50. })
  51. .and_then(|r| {
  52. r.success().map_err(|_| {
  53. Error::Authfailed(format!("Wrong username or password"))
  54. })
  55. })
  56. .and(Ok(User{uid: uid, groups: vec!("coucou".to_string())})) //TODO: add groups
  57. }
  58. pub async fn change_password(&self, username: String, password: String, new_password: String) -> Result<(), Error> {
  59. let mut salt = [0u8; 4];
  60. let salt_generator = rand::SystemRandom::new();
  61. let _ = salt_generator.fill(&mut salt);
  62. let mut password_bytes = new_password.into_bytes();
  63. //adding salt to the end of the password
  64. salt.map(|elem| {
  65. password_bytes.push(elem);
  66. });
  67. //Getting sha512 sum
  68. let mut hasher = Sha512::new();
  69. hasher.update(password_bytes);
  70. let mut hash = hasher.finalize().as_slice().to_vec();
  71. //Adding salt to the end of hash
  72. salt.map(|elem| {
  73. hash.push(elem);
  74. });
  75. let b64_new_password = format!("{{SSHA512}}{}", STANDARD.encode(hash));
  76. let mut ldap = self.ldap_pool.get().await.unwrap();
  77. let _ = ldap.simple_bind(format!("uid={},{}", username, self.config.basedn).as_str(), &password)
  78. .await
  79. .map_err(|_| {
  80. Error::Authfailed(format!("Wrong current password"))
  81. }).and_then(|r| {
  82. r.success().map_err(|_| {
  83. Error::Authfailed(format!("Wrong current password"))
  84. })
  85. });
  86. let hashset= HashSet::from([b64_new_password.as_str()]);
  87. let data = vec![ldap3::Mod::Replace("userPassword", hashset)];
  88. ldap.modify(format!("uid={},{}", username, self.config.basedn).as_str(), data)
  89. .await
  90. .map_err(|e| {
  91. Error::LdapServerError(format!("An error occured, contact admins: {}", e))
  92. })
  93. .and_then(|r| {
  94. r.success().map_err(|e| {
  95. Error::LdapServerError(format!("An error occured, contact admins: {}", e))
  96. })
  97. })
  98. .and(Ok(()))
  99. }
  100. }