use serde::{Deserialize, Serialize};
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub enum OperatorRole {
ClusterAdmin,
TenantAdmin,
BucketAdmin,
Auditor,
ReadOnlyOperator,
SecurityOfficer,
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub enum OperatorAction {
AdministerCluster,
AdministerTenant,
AdministerBucket,
ReadDiagnostics,
ReadAudit,
ManageSecurity,
ManageCredentials,
SimulatePolicy,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub struct RoleAssignment {
pub principal_id: String,
pub role: OperatorRole,
pub scope: String,
}
impl RoleAssignment {
pub fn new(
principal_id: impl Into<String>,
role: OperatorRole,
scope: impl Into<String>,
) -> Self {
Self {
principal_id: principal_id.into(),
role,
scope: scope.into(),
}
}
pub fn permits(&self, action: OperatorAction, resource: &str) -> bool {
match self.role {
OperatorRole::ClusterAdmin => self.scope_matches(resource),
OperatorRole::TenantAdmin => {
matches!(
action,
OperatorAction::AdministerTenant
| OperatorAction::ReadDiagnostics
| OperatorAction::ReadAudit
| OperatorAction::SimulatePolicy
) && self.scope_matches(resource)
}
OperatorRole::BucketAdmin => {
matches!(
action,
OperatorAction::AdministerBucket
| OperatorAction::ReadDiagnostics
| OperatorAction::SimulatePolicy
) && self.scope_matches(resource)
}
OperatorRole::Auditor => {
matches!(action, OperatorAction::ReadAudit) && self.scope_matches(resource)
}
OperatorRole::ReadOnlyOperator => {
matches!(
action,
OperatorAction::ReadDiagnostics | OperatorAction::ReadAudit
) && self.scope_matches(resource)
}
OperatorRole::SecurityOfficer => {
matches!(
action,
OperatorAction::ManageSecurity
| OperatorAction::ManageCredentials
| OperatorAction::SimulatePolicy
| OperatorAction::ReadAudit
) && self.scope_matches(resource)
}
}
}
fn scope_matches(&self, resource: &str) -> bool {
self.scope == "*" || self.scope == resource || resource.starts_with(self.scope.as_str())
}
}