Skip to main content

bucketwarden_auth/
admin_roles.rs

1use serde::{Deserialize, Serialize};
2
3#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
4pub enum OperatorRole {
5    ClusterAdmin,
6    TenantAdmin,
7    BucketAdmin,
8    Auditor,
9    ReadOnlyOperator,
10    SecurityOfficer,
11}
12
13#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
14pub enum OperatorAction {
15    AdministerCluster,
16    AdministerTenant,
17    AdministerBucket,
18    ReadDiagnostics,
19    ReadAudit,
20    ManageSecurity,
21    ManageCredentials,
22    SimulatePolicy,
23}
24
25#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
26pub struct RoleAssignment {
27    pub principal_id: String,
28    pub role: OperatorRole,
29    pub scope: String,
30}
31
32impl RoleAssignment {
33    pub fn new(
34        principal_id: impl Into<String>,
35        role: OperatorRole,
36        scope: impl Into<String>,
37    ) -> Self {
38        Self {
39            principal_id: principal_id.into(),
40            role,
41            scope: scope.into(),
42        }
43    }
44
45    pub fn permits(&self, action: OperatorAction, resource: &str) -> bool {
46        match self.role {
47            OperatorRole::ClusterAdmin => self.scope_matches(resource),
48            OperatorRole::TenantAdmin => {
49                matches!(
50                    action,
51                    OperatorAction::AdministerTenant
52                        | OperatorAction::ReadDiagnostics
53                        | OperatorAction::ReadAudit
54                        | OperatorAction::SimulatePolicy
55                ) && self.scope_matches(resource)
56            }
57            OperatorRole::BucketAdmin => {
58                matches!(
59                    action,
60                    OperatorAction::AdministerBucket
61                        | OperatorAction::ReadDiagnostics
62                        | OperatorAction::SimulatePolicy
63                ) && self.scope_matches(resource)
64            }
65            OperatorRole::Auditor => {
66                matches!(action, OperatorAction::ReadAudit) && self.scope_matches(resource)
67            }
68            OperatorRole::ReadOnlyOperator => {
69                matches!(
70                    action,
71                    OperatorAction::ReadDiagnostics | OperatorAction::ReadAudit
72                ) && self.scope_matches(resource)
73            }
74            OperatorRole::SecurityOfficer => {
75                matches!(
76                    action,
77                    OperatorAction::ManageSecurity
78                        | OperatorAction::ManageCredentials
79                        | OperatorAction::SimulatePolicy
80                        | OperatorAction::ReadAudit
81                ) && self.scope_matches(resource)
82            }
83        }
84    }
85
86    fn scope_matches(&self, resource: &str) -> bool {
87        self.scope == "*" || self.scope == resource || resource.starts_with(self.scope.as_str())
88    }
89}