backbone_authorization/
service.rs1use crate::cache::{InMemoryPermissionCache, PermissionCacheBackend};
7use crate::traits::*;
8use crate::types::*;
9use async_trait::async_trait;
10use std::collections::{HashMap, HashSet};
11use std::sync::Arc;
12use tokio::sync::RwLock;
13use tracing::{debug, info};
14
15pub struct AuthorizationService {
17 role_permissions: Arc<RwLock<HashMap<String, HashSet<Permission>>>>,
19
20 user_roles: Arc<RwLock<HashMap<String, HashSet<String>>>>,
22
23 cache: Arc<dyn PermissionCacheBackend>,
25
26 config: AuthorizationConfig,
28}
29
30impl Default for AuthorizationService {
31 fn default() -> Self {
32 Self::new()
33 }
34}
35
36impl AuthorizationService {
37 pub fn new() -> Self {
39 Self::with_cache(Arc::new(InMemoryPermissionCache::new()))
40 }
41
42 pub fn with_cache(cache: Arc<dyn PermissionCacheBackend>) -> Self {
44 Self::with_config(AuthorizationConfig::default(), cache)
45 }
46
47 pub fn with_config(config: AuthorizationConfig, cache: Arc<dyn PermissionCacheBackend>) -> Self {
49 let service = Self {
50 role_permissions: Arc::new(RwLock::new(HashMap::new())),
51 user_roles: Arc::new(RwLock::new(HashMap::new())),
52 cache,
53 config,
54 };
55
56 let role_perms = service.role_permissions.clone();
58 tokio::spawn(async move {
59 Self::initialize_default_roles_static(role_perms).await;
60 });
61
62 service
63 }
64
65 async fn initialize_default_roles_static(
67 role_permissions: Arc<RwLock<HashMap<String, HashSet<Permission>>>>,
68 ) {
69 info!("Initializing default RBAC roles and permissions");
70
71 let mut role_perms = role_permissions.write().await;
72
73 let super_admin_perms: HashSet<Permission> = Permission::all_permissions();
75 role_perms.insert("super_admin".to_string(), super_admin_perms);
76
77 let admin_perms: HashSet<Permission> = Permission::all_permissions()
79 .into_iter()
80 .filter(|p| !matches!(p, Permission::User(_)))
81 .collect();
82 role_perms.insert("admin".to_string(), admin_perms);
83
84 let user_perms: HashSet<Permission> = [
86 Permission::User(UserAction::Read),
87 Permission::Settings(SettingsAction::Read),
88 Permission::Role(RoleAction::Read),
89 Permission::Permission(PermissionAction::Read),
90 ]
91 .into_iter()
92 .collect();
93 role_perms.insert("user".to_string(), user_perms);
94
95 let guest_perms: HashSet<Permission> = [
97 Permission::User(UserAction::Read),
98 Permission::Settings(SettingsAction::Read),
99 ]
100 .into_iter()
101 .collect();
102 role_perms.insert("guest".to_string(), guest_perms);
103
104 info!("Initialized {} default roles", role_perms.len());
105 }
106
107 async fn get_cached_permissions(&self, user_id: &str) -> HashSet<Permission> {
109 if self.config.enable_permission_caching {
111 if let Ok(Some(permissions)) = self.cache.get(user_id).await {
112 debug!("Using cached permissions for user '{}'", user_id);
113 return permissions;
114 }
115 }
116
117 let permissions = self.fetch_user_permissions(user_id).await;
119
120 if self.config.enable_permission_caching {
122 if let Err(e) = self.cache.set(user_id, &permissions, self.config.cache_ttl_seconds).await {
123 tracing::warn!("Failed to cache permissions for user '{}': {}", user_id, e);
124 }
125 }
126
127 permissions
128 }
129
130 async fn fetch_user_permissions(&self, user_id: &str) -> HashSet<Permission> {
132 let roles = self.user_roles.read().await;
133 let user_roles = roles.get(user_id).cloned().unwrap_or_default();
134
135 let role_perms = self.role_permissions.read().await;
136 let mut permissions = HashSet::new();
137
138 for role in user_roles {
139 if let Some(role_perms) = role_perms.get(&role) {
140 permissions.extend(role_perms.clone());
141 }
142 }
143
144 if permissions.is_empty() {
146 if let Some(guest_perms) = role_perms.get("guest") {
147 permissions.extend(guest_perms.clone());
148 }
149 }
150
151 permissions
152 }
153
154 pub async fn clear_user_cache(&self, user_id: &str) {
156 if let Err(e) = self.cache.delete(user_id).await {
157 tracing::warn!("Failed to clear cache for user '{}': {}", user_id, e);
158 }
159 debug!("Cleared permission cache for user '{}'", user_id);
160 }
161
162 pub async fn clear_all_cache(&self) {
164 if let Err(e) = self.cache.clear().await {
165 tracing::warn!("Failed to clear all permission caches: {}", e);
166 }
167 info!("Cleared all permission caches");
168 }
169}
170
171#[async_trait]
172impl AuthorizationServiceTrait for AuthorizationService {
173 async fn check_authorization(
174 &self,
175 request: AuthorizationRequest,
176 ) -> Result<AuthorizationResponse, AuthorizationError> {
177 let user_id = &request.user.user_id;
178
179 let permissions = self.get_cached_permissions(user_id).await;
181
182 let required_permission = Permission::from_action_resource(
184 request.action.clone(),
185 request.resource.clone(),
186 );
187
188 let has_permission = permissions.contains(&required_permission);
189
190 let response = AuthorizationResponse {
191 allowed: has_permission,
192 checks: vec![PermissionCheck {
193 allowed: has_permission,
194 permission: required_permission.clone(),
195 reason: if has_permission {
196 "Permission granted".to_string()
197 } else {
198 format!("Missing permission: {:?}", required_permission)
199 },
200 }],
201 };
202
203 debug!(
204 "Authorization check for user '{}': {}",
205 user_id,
206 if has_permission { "ALLOWED" } else { "DENIED" }
207 );
208
209 Ok(response)
210 }
211
212 async fn grant_permission_to_role(
213 &self,
214 role: &str,
215 permission: Permission,
216 ) -> Result<(), AuthorizationError> {
217 info!("Granted permission {:?} to role '{}'", permission, role);
218
219 let mut role_perms = self.role_permissions.write().await;
220 role_perms
221 .entry(role.to_string())
222 .or_insert_with(HashSet::new)
223 .insert(permission);
224
225 Ok(())
226 }
227
228 async fn revoke_permission_from_role(
229 &self,
230 role: &str,
231 permission: &Permission,
232 ) -> Result<(), AuthorizationError> {
233 let mut role_perms = self.role_permissions.write().await;
234 if let Some(perms) = role_perms.get_mut(role) {
235 perms.remove(permission);
236 info!("Revoked permission {:?} from role '{}'", permission, role);
237 }
238 Ok(())
239 }
240
241 async fn assign_role_to_user(
242 &self,
243 user_id: &str,
244 role: &str,
245 ) -> Result<(), AuthorizationError> {
246 let mut user_roles = self.user_roles.write().await;
247 user_roles
248 .entry(user_id.to_string())
249 .or_insert_with(HashSet::new)
250 .insert(role.to_string());
251
252 self.clear_user_cache(user_id).await;
254
255 info!("Assigned role '{}' to user '{}'", role, user_id);
256 Ok(())
257 }
258
259 async fn remove_role_from_user(
260 &self,
261 user_id: &str,
262 role: &str,
263 ) -> Result<(), AuthorizationError> {
264 let mut user_roles = self.user_roles.write().await;
265 if let Some(roles) = user_roles.get_mut(user_id) {
266 roles.remove(role);
267 }
268
269 self.clear_user_cache(user_id).await;
271
272 info!("Removed role '{}' from user '{}'", role, user_id);
273 Ok(())
274 }
275
276 async fn get_user_permissions(
277 &self,
278 user_id: &str,
279 ) -> Result<Vec<Permission>, AuthorizationError> {
280 let permissions = self.get_cached_permissions(user_id).await;
281 Ok(permissions.into_iter().collect())
282 }
283
284 async fn user_has_permission(
285 &self,
286 user_id: &str,
287 permission: &Permission,
288 ) -> Result<bool, AuthorizationError> {
289 let permissions = self.get_cached_permissions(user_id).await;
290 Ok(permissions.contains(permission))
291 }
292}
293
294pub type InMemoryAuthService = AuthorizationService;