Skip to main content

csh_ldap/
user.rs

1use lazy_static::lazy_static;
2use ldap3::SearchEntry;
3use regex::Regex;
4use serde::{Deserialize, Serialize};
5use std::collections::HashMap;
6use std::fmt::Debug;
7use std::str::FromStr;
8
9#[derive(Debug, Serialize, Deserialize, Clone)]
10#[allow(non_snake_case)]
11pub struct LdapUser {
12    pub dn: String,
13    pub cn: String,
14    pub uid: String,
15    pub groups: Vec<String>,
16    pub krbPrincipalName: String,
17    pub mail: Vec<String>,
18    pub mobile: Vec<String>,
19    pub drinkBalance: Option<i64>,
20    pub ibutton: Vec<String>,
21}
22
23impl LdapUser {
24    #[must_use]
25    pub fn from_entry(entry: &SearchEntry) -> Self {
26        let user_attrs = &entry.attrs;
27        LdapUser {
28            dn: entry.dn.clone(),
29            cn: get_one(user_attrs, "cn").unwrap(),
30            uid: get_one(user_attrs, "uid").unwrap(),
31            groups: get_groups(get_vec(user_attrs, "memberOf")),
32            krbPrincipalName: get_one(user_attrs, "krbPrincipalName").unwrap(),
33            mail: get_vec(user_attrs, "mail"),
34            mobile: get_vec(user_attrs, "mobile"),
35            ibutton: get_vec(user_attrs, "ibutton"),
36            drinkBalance: get_one(user_attrs, "drinkBalance"),
37        }
38    }
39}
40
41fn get_one<T>(entry: &HashMap<String, Vec<String>>, field: &str) -> Option<T>
42where
43    T: FromStr,
44    <T as FromStr>::Err: Debug,
45{
46    match entry.get(field).map(|f| f.get(0).unwrap().parse::<T>()) {
47        Some(result) => match result {
48            Ok(r) => Some(r),
49            Err(_) => None,
50        },
51        None => None,
52    }
53}
54
55fn get_vec<T>(entry: &HashMap<String, Vec<String>>, field: &str) -> Vec<T>
56where
57    T: FromStr,
58    <T as FromStr>::Err: Debug,
59{
60    match entry.get(field) {
61        Some(v) => v.iter().map(|f| f.parse::<T>().unwrap()).collect(),
62        None => vec![],
63    }
64}
65
66#[must_use]
67pub fn get_groups(member_of: Vec<String>) -> Vec<String> {
68    lazy_static! {
69        static ref GROUP_REGEX: Regex =
70            Regex::new(r"cn=(?P<name>\w+),cn=groups,cn=accounts,dc=csh,dc=rit,dc=edu").unwrap();
71    }
72    member_of
73        .iter()
74        .filter_map(|group| {
75            GROUP_REGEX
76                .captures(group)
77                .map(|cap| cap["name"].to_owned())
78        })
79        .collect()
80}
81
82#[derive(Debug, Serialize, Deserialize)]
83#[allow(non_snake_case)]
84pub struct LdapUserChangeSet {
85    pub dn: String,
86    pub drinkBalance: Option<i64>,
87    pub ibutton: Option<Vec<String>>,
88}