Skip to main content

openauth_plugins/admin/
access.rs

1use 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}