1use std::collections::HashMap;
8
9use serde::{Deserialize, Serialize};
10
11use crate::{AuthError, error::Result, middleware::AuthenticatedUser};
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
19#[non_exhaustive]
20pub enum OperationPermission {
21 CreateRule,
23 UpdateRule,
25 DeleteRule,
27 ExecuteRule,
29
30 CreateAction,
32 UpdateAction,
34 DeleteAction,
36 ExecuteAction,
38
39 ManageWebhooks,
41 ManageSecrets,
43 ManageUsers,
45 ManageRoles,
47 ManageTenants,
49
50 ExportData,
52 ImportData,
54 DeleteData,
56
57 ViewAuditLogs,
59 ManageConfiguration,
61 ManageIntegrations,
63}
64
65impl OperationPermission {
66 #[must_use]
68 pub const fn name(&self) -> &'static str {
69 match self {
70 Self::CreateRule => "Create Observer Rule",
71 Self::UpdateRule => "Update Observer Rule",
72 Self::DeleteRule => "Delete Observer Rule",
73 Self::ExecuteRule => "Execute Observer Rule",
74 Self::CreateAction => "Create Action",
75 Self::UpdateAction => "Update Action",
76 Self::DeleteAction => "Delete Action",
77 Self::ExecuteAction => "Execute Action",
78 Self::ManageWebhooks => "Manage Webhooks",
79 Self::ManageSecrets => "Manage Secrets",
80 Self::ManageUsers => "Manage Users",
81 Self::ManageRoles => "Manage Roles",
82 Self::ManageTenants => "Manage Tenants",
83 Self::ExportData => "Export Data",
84 Self::ImportData => "Import Data",
85 Self::DeleteData => "Delete Data",
86 Self::ViewAuditLogs => "View Audit Logs",
87 Self::ManageConfiguration => "Manage Configuration",
88 Self::ManageIntegrations => "Manage Integrations",
89 }
90 }
91
92 #[must_use]
94 pub const fn as_str(&self) -> &'static str {
95 match self {
96 Self::CreateRule => "create_rule",
97 Self::UpdateRule => "update_rule",
98 Self::DeleteRule => "delete_rule",
99 Self::ExecuteRule => "execute_rule",
100 Self::CreateAction => "create_action",
101 Self::UpdateAction => "update_action",
102 Self::DeleteAction => "delete_action",
103 Self::ExecuteAction => "execute_action",
104 Self::ManageWebhooks => "manage_webhooks",
105 Self::ManageSecrets => "manage_secrets",
106 Self::ManageUsers => "manage_users",
107 Self::ManageRoles => "manage_roles",
108 Self::ManageTenants => "manage_tenants",
109 Self::ExportData => "export_data",
110 Self::ImportData => "import_data",
111 Self::DeleteData => "delete_data",
112 Self::ViewAuditLogs => "view_audit_logs",
113 Self::ManageConfiguration => "manage_configuration",
114 Self::ManageIntegrations => "manage_integrations",
115 }
116 }
117}
118
119#[derive(Debug, Clone)]
121pub struct Role {
122 pub name: String,
124 pub permissions: Vec<OperationPermission>,
126}
127
128impl Role {
129 #[must_use]
131 pub const fn new(name: String, permissions: Vec<OperationPermission>) -> Self {
132 Self { name, permissions }
133 }
134
135 #[must_use]
137 pub fn has_permission(&self, permission: OperationPermission) -> bool {
138 self.permissions.contains(&permission)
139 }
140
141 #[must_use]
143 pub fn get_permissions(&self) -> &[OperationPermission] {
144 &self.permissions
145 }
146}
147
148#[derive(Debug, Clone)]
150pub struct RBACPolicy {
151 roles: HashMap<String, Role>,
152}
153
154impl Default for RBACPolicy {
155 fn default() -> Self {
156 Self::new()
157 }
158}
159
160impl RBACPolicy {
161 #[must_use]
163 pub fn new() -> Self {
164 let mut roles = HashMap::new();
165
166 roles.insert(
168 "admin".to_string(),
169 Role::new(
170 "admin".to_string(),
171 vec![
172 OperationPermission::CreateRule,
173 OperationPermission::UpdateRule,
174 OperationPermission::DeleteRule,
175 OperationPermission::ExecuteRule,
176 OperationPermission::CreateAction,
177 OperationPermission::UpdateAction,
178 OperationPermission::DeleteAction,
179 OperationPermission::ExecuteAction,
180 OperationPermission::ManageWebhooks,
181 OperationPermission::ManageSecrets,
182 OperationPermission::ManageUsers,
183 OperationPermission::ManageRoles,
184 OperationPermission::ManageTenants,
185 OperationPermission::ExportData,
186 OperationPermission::ImportData,
187 OperationPermission::DeleteData,
188 OperationPermission::ViewAuditLogs,
189 OperationPermission::ManageConfiguration,
190 OperationPermission::ManageIntegrations,
191 ],
192 ),
193 );
194
195 roles.insert(
197 "operator".to_string(),
198 Role::new(
199 "operator".to_string(),
200 vec![
201 OperationPermission::CreateRule,
202 OperationPermission::UpdateRule,
203 OperationPermission::DeleteRule,
204 OperationPermission::ExecuteRule,
205 OperationPermission::CreateAction,
206 OperationPermission::UpdateAction,
207 OperationPermission::DeleteAction,
208 OperationPermission::ExecuteAction,
209 OperationPermission::ManageWebhooks,
210 OperationPermission::ExportData,
211 OperationPermission::ViewAuditLogs,
212 ],
213 ),
214 );
215
216 roles.insert(
218 "viewer".to_string(),
219 Role::new(
220 "viewer".to_string(),
221 vec![
222 OperationPermission::ExportData,
223 OperationPermission::ViewAuditLogs,
224 ],
225 ),
226 );
227
228 Self { roles }
229 }
230
231 pub fn register_role(&mut self, role: Role) {
233 self.roles.insert(role.name.clone(), role);
234 }
235
236 pub fn authorize(
242 &self,
243 user: &AuthenticatedUser,
244 permission: OperationPermission,
245 ) -> Result<()> {
246 let user_roles = self.extract_user_roles(user);
248
249 for role_name in user_roles {
251 if let Some(role) = self.roles.get(&role_name) {
252 if role.has_permission(permission) {
253 return Ok(());
254 }
255 }
256 }
257
258 Err(AuthError::Forbidden {
259 message: format!(
260 "User {} does not have permission to: {}",
261 user.user_id,
262 permission.name()
263 ),
264 })
265 }
266
267 pub fn authorize_any(
273 &self,
274 user: &AuthenticatedUser,
275 permissions: &[OperationPermission],
276 ) -> Result<()> {
277 for permission in permissions {
278 if self.authorize(user, *permission).is_ok() {
279 return Ok(());
280 }
281 }
282
283 Err(AuthError::Forbidden {
284 message: format!("User {} does not have any of the required permissions", user.user_id),
285 })
286 }
287
288 pub fn authorize_all(
294 &self,
295 user: &AuthenticatedUser,
296 permissions: &[OperationPermission],
297 ) -> Result<()> {
298 for permission in permissions {
299 self.authorize(user, *permission)?;
300 }
301 Ok(())
302 }
303
304 #[must_use]
306 pub fn get_user_permissions(&self, user: &AuthenticatedUser) -> Vec<OperationPermission> {
307 let user_roles = self.extract_user_roles(user);
308 let mut permissions = Vec::new();
309
310 for role_name in user_roles {
311 if let Some(role) = self.roles.get(&role_name) {
312 permissions.extend(role.get_permissions());
313 }
314 }
315
316 permissions.sort_by_key(|p| *p as u32);
318 permissions.dedup();
319
320 permissions
321 }
322
323 fn extract_user_roles(&self, user: &AuthenticatedUser) -> Vec<String> {
325 let mut roles = Vec::new();
326
327 if let Some(serde_json::Value::String(role)) = user.get_custom_claim("role") {
329 roles.push(role.clone());
330 }
331
332 if let Some(serde_json::Value::Array(role_array)) = user.get_custom_claim("roles") {
334 for role_val in role_array {
335 if let serde_json::Value::String(role_name) = role_val {
336 roles.push(role_name.clone());
337 }
338 }
339 }
340
341 if let Some(serde_json::Value::Array(role_array)) = user.get_custom_claim("fraiseql_roles")
343 {
344 for role_val in role_array {
345 if let serde_json::Value::String(role_name) = role_val {
346 roles.push(role_name.clone());
347 }
348 }
349 }
350
351 roles.sort();
353 roles.dedup();
354
355 roles
356 }
357}