openauth_plugins/admin/
access.rs1use std::collections::BTreeMap;
2
3use crate::access::{
4 create_access_control, request as access_request, role as access_role, statements,
5 AccessControl, AccessError, Role as AccessRole, Statements,
6};
7
8use super::options::AdminOptions;
9
10pub type PermissionMap = BTreeMap<String, Vec<String>>;
11
12#[derive(Debug, Clone, PartialEq, Eq)]
13pub struct Role {
14 access_role: AccessRole,
15}
16
17impl Role {
18 pub fn new(permissions: PermissionMap) -> Self {
19 let permissions = permissions
20 .into_iter()
21 .map(|(resource, actions)| (resource, actions.into_iter().collect()))
22 .collect::<Statements>();
23 let access_role = access_role(permissions);
24
25 Self { access_role }
26 }
27
28 pub fn allows(&self, requested: &PermissionMap) -> bool {
29 if requested.is_empty() {
30 return true;
31 }
32
33 self.access_role
34 .authorize_all(access_request(
35 requested
36 .iter()
37 .map(|(resource, actions)| (resource.clone(), actions.clone())),
38 ))
39 .is_ok()
40 }
41}
42
43pub fn has_permission(
44 user_id: Option<&str>,
45 role: Option<&str>,
46 options: &AdminOptions,
47 permissions: &PermissionMap,
48) -> bool {
49 if user_id.is_some_and(|id| options.admin_user_ids.iter().any(|admin_id| admin_id == id)) {
50 return true;
51 }
52
53 let role = role.unwrap_or(&options.default_role);
54 for role_name in role
55 .split(',')
56 .map(str::trim)
57 .filter(|item| !item.is_empty())
58 {
59 if options
60 .roles
61 .get(role_name)
62 .is_some_and(|role| role.allows(permissions))
63 {
64 return true;
65 }
66 }
67 false
68}
69
70pub fn default_roles() -> BTreeMap<String, Role> {
71 let mut roles = BTreeMap::new();
72 roles.insert("admin".to_owned(), admin_role());
73 roles.insert("user".to_owned(), Role::new(PermissionMap::new()));
74 roles
75}
76
77pub fn default_statements() -> Statements {
78 statements([
79 (
80 "user",
81 vec![
82 "create",
83 "list",
84 "set-role",
85 "ban",
86 "impersonate",
87 "impersonate-admins",
88 "delete",
89 "set-password",
90 "get",
91 "update",
92 ],
93 ),
94 ("session", vec!["list", "revoke", "delete"]),
95 ])
96}
97
98pub fn default_access_control() -> Result<AccessControl, AccessError> {
99 create_access_control(default_statements())
100}
101
102fn admin_role() -> Role {
103 Role::new(PermissionMap::from([
104 (
105 "user".to_owned(),
106 vec![
107 "create".to_owned(),
108 "list".to_owned(),
109 "set-role".to_owned(),
110 "ban".to_owned(),
111 "impersonate".to_owned(),
112 "delete".to_owned(),
113 "set-password".to_owned(),
114 "get".to_owned(),
115 "update".to_owned(),
116 ],
117 ),
118 (
119 "session".to_owned(),
120 vec!["list".to_owned(), "revoke".to_owned(), "delete".to_owned()],
121 ),
122 ]))
123}