Переглянути джерело

Users infos such as groups and pubkey capability are now fetched and stored

clement 1 рік тому
батько
коміт
339465924a
4 змінених файлів з 36 додано та 7 видалено
  1. 33 7
      src/ldap/lib.rs
  2. 1 0
      src/ldap/pool.rs
  3. 1 0
      src/main.rs
  4. 1 0
      src/settings.toml.example

+ 33 - 7
src/ldap/lib.rs

@@ -1,4 +1,4 @@
-use std::collections::HashSet;
+use std::{collections::HashSet, vec};
 use base64::{engine::general_purpose::STANDARD, Engine as _};
 use deadpool::managed::Pool;
 use ldap3::SearchEntry;
@@ -12,7 +12,7 @@ use pool::{get_ldap_pool, LdapConfig, LdapManager};
 
 pub enum Error {
     Authfailed(String),
-    LdapServerError(String)
+    LdapServerError(String),
 }
 #[derive(Clone)]
 pub struct LdapWrapper {
@@ -22,6 +22,7 @@ pub struct LdapWrapper {
 
 pub struct User {
     pub uid: String,
+    pub is_ssh: bool,
     pub groups: Vec<String>,
 }
 
@@ -31,6 +32,29 @@ impl LdapWrapper {
         LdapWrapper{ldap_pool, config}
     }
 
+    async fn get_user_infos(&self, uid: &String) -> Result<(bool, Vec<String>), Error> {
+        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"])
+        .await.map_err(|e| {Error::LdapServerError(format!("Error: {}", e))})?;
+
+        let (result_entry, _ldap_res) = search_res.success().map_err(|e| {Error::LdapServerError(format!("Error: {}", e))})?;
+
+        if result_entry.is_empty() {
+            return Err(Error::LdapServerError(format!("Error contact admins: dn shouldn't be empty")));
+        }
+
+        let records = SearchEntry::construct(result_entry.first().unwrap().to_owned());
+
+        let is_ssh = records.attrs.get("objectClass").unwrap().contains(&"ldapPublicKey".to_string());
+        let groups: Vec<String> = records.attrs.get("memberOf").unwrap().iter()
+        .map(|elem| {
+            elem.replace(&format!(",{}", self.config.groupsdn).to_string(), "")
+            .replace("cn=", "")
+        }).collect();
+
+        Ok((is_ssh, groups))
+    }
+    
     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();
@@ -38,16 +62,16 @@ impl LdapWrapper {
         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"))})?;
+            .await.map_err(|e| {Error::LdapServerError(format!("Error: {}", e))})?;
 
-            let (result_entry, _ldap_res) = search_res.success().map_err(|_| {Error::Authfailed(format!("Wrong username or password"))})?;
+            let (result_entry, _ldap_res) = search_res.success().map_err(|e| {Error::LdapServerError(format!("Error: {}", e))})?;
 
             if result_entry.is_empty() {
-                return Err(Error::Authfailed(format!("No record found")));
+                return Err(Error::Authfailed(format!("Wrong username or password")));
             }
 
             if result_entry.len() > 1 {
-                return Err(Error::Authfailed(format!("Multiple records found")));
+                return Err(Error::Authfailed(format!("Error contact admins")));
             }
 
             let records = SearchEntry::construct(result_entry.first().unwrap().to_owned());
@@ -66,7 +90,9 @@ impl LdapWrapper {
                 Error::Authfailed(format!("Wrong username or password"))
             })
         })
-        .and(Ok(User{uid: uid, groups: vec!("coucou".to_string())})) //TODO: add groups
+        .and({
+            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> {

+ 1 - 0
src/ldap/pool.rs

@@ -6,6 +6,7 @@ pub struct LdapConfig {
     pub hostname: String,
     pub port: String,
     pub basedn: String,
+    pub groupsdn: String,
     pub binddn: String,
     pub bindpw: String,
     pub starttls: bool,

+ 1 - 0
src/main.rs

@@ -30,6 +30,7 @@ async fn main() -> std::io::Result<()> {
         hostname: settings.get("hostname").unwrap(),
         port: settings.get("port").unwrap(),
         basedn: settings.get("basedn").unwrap(),
+        groupsdn: settings.get("groupsdn").unwrap(),
         binddn: settings.get("binddn").unwrap(),
         bindpw: settings.get("bindpw").unwrap(),
         starttls: settings.get("starttls").unwrap(),

+ 1 - 0
src/settings.toml.example

@@ -1,6 +1,7 @@
 hostname = "example.com"
 port = "389"
 basedn = "ou=people,dc=example,dc=com"
+groupsdn = "ou=Groups,dc=example,dc=com"
 binddn = ""
 bindpw = ""
 starttls = false