bucketwarden_auth/
admin_roles.rs1use 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}