//! I'm working towards making this a proper enumeration/discovery toolkit for access things in Kanidm. //! //! - @yaleman //! use kanidmd_lib::constants::entries::Attribute; use kanidmd_lib::constants::groups::{idm_builtin_admin_groups, idm_builtin_non_admin_groups}; use kanidmd_lib::prelude::{builtin_accounts, EntryInitNew}; use petgraph::graphmap::{AllEdges, GraphMap, NodeTrait}; use petgraph::Directed; use serde::{Deserialize, Serialize}; use std::collections::{BTreeMap, BTreeSet}; use uuid::Uuid; #[derive(Clone, Deserialize, Serialize)] enum EdgeType { MemberOf, } #[derive(Debug)] enum EntryType { Person(String), ServiceAccount(String), Group(String), UnknownType(String), } impl EntryType { fn as_mermaid_tag(&self) -> String { match self { EntryType::Person(name) => format!("{}(\"Person:{}\")", name, name), EntryType::ServiceAccount(name) => format!("{}{{\"SA: {}\"}}", name, name), EntryType::Group(name) => format!("{}[\"Group: {}\"]", name, name), EntryType::UnknownType(name) => format!("{}[\"Unknown Type {}\"]", name, name), } } } impl From<&EntryInitNew> for EntryType { fn from(entry: &EntryInitNew) -> Self { let name = entry.get_ava_single(Attribute::Name).unwrap(); let name = name.as_string().unwrap(); let classes = entry .get_ava_set(Attribute::Class) .unwrap() .as_iutf8_set() .cloned() .unwrap_or(BTreeSet::::new()); if classes.contains("group") { EntryType::Group(name.clone()) } else if classes.contains("service_account") { EntryType::ServiceAccount(name.clone()) } else if classes.contains("person") { EntryType::Person(name.clone()) } else { EntryType::UnknownType(name.clone()) } } } struct Graph(GraphMap); impl Graph where T: core::hash::Hash + Ord + NodeTrait, { fn new() -> Self { Graph(GraphMap::::new()) } fn add_node(&mut self, n: T) { self.0.add_node(n); } fn add_edge(&mut self, l: T, r: T, t: EdgeType) { self.0.add_edge(l, r, t); } fn all_edges(&mut self) -> AllEdges<'_, T, EdgeType, Directed> { self.0.all_edges() } /// The uuidmap is a map of uuids to EntryInitNew objects, which we use to get the name of the objects fn as_mermaid(&mut self, uuidmap: &BTreeMap) -> String { let mut res = "graph RL;\n".to_string(); for (left, right, _weight) in self.all_edges() { let left = uuidmap.get(&left).unwrap(); let right = uuidmap.get(&right).unwrap(); res = format!( "{} {} --> {}\n", res, EntryType::from(left).as_mermaid_tag(), EntryType::from(right).as_mermaid_tag(), ); } res } } async fn enumerate_default_groups(/*_client: KanidmClient*/) { let mut uuidmap: BTreeMap = BTreeMap::new(); let mut graph = Graph::new(); builtin_accounts().into_iter().for_each(|account| { // println!("adding builtin {}", account.uuid); uuidmap.insert(account.uuid, account.clone().into()); graph.add_node(account.uuid); }); let mut groups = idm_builtin_admin_groups(); groups.extend(idm_builtin_non_admin_groups()); groups.into_iter().for_each(|group| { uuidmap.insert(group.uuid, group.clone().try_into().unwrap()); graph.add_node(group.uuid); // handle the membership group.members.iter().for_each(|member| { graph.add_edge(*member, group.uuid, EdgeType::MemberOf); }); }); println!("{}", graph.as_mermaid(&uuidmap)) } #[tokio::main] async fn main() { enumerate_default_groups().await; }