1use crate::providers::ProviderError;
47use crate::providers::ResourceProvider;
48use crate::providers::helpers::{
49 metadata::ScimMetadataManager, patch::ScimPatchOperations, tenant::MultiTenantProvider,
50};
51use crate::resource::{
52 ListQuery, RequestContext, Resource, version::RawVersion, versioned::VersionedResource,
53};
54use crate::storage::ProviderStats;
55use crate::storage::{StorageKey, StorageProvider};
56use log::{debug, info, trace, warn};
57use serde_json::{Value, json};
58
59#[derive(Debug, Clone)]
65pub struct StandardResourceProvider<S: StorageProvider> {
66 storage: S,
68}
69
70impl<S: StorageProvider> StandardResourceProvider<S> {
71 pub fn new(storage: S) -> Self {
73 Self { storage }
74 }
75
76 async fn check_username_duplicate(
78 &self,
79 tenant_id: &str,
80 username: &str,
81 exclude_id: Option<&str>,
82 ) -> Result<(), ProviderError> {
83 let prefix = StorageKey::prefix(tenant_id, "User");
84 let matches = self
85 .storage
86 .find_by_attribute(prefix, "userName", username)
87 .await
88 .map_err(|e| ProviderError::Internal {
89 message: format!("Storage error during username check: {}", e),
90 })?;
91
92 for (key, _data) in matches {
93 if Some(key.resource_id()) != exclude_id {
95 return Err(ProviderError::DuplicateAttribute {
96 resource_type: "User".to_string(),
97 attribute: "userName".to_string(),
98 value: username.to_string(),
99 tenant_id: tenant_id.to_string(),
100 });
101 }
102 }
103
104 Ok(())
105 }
106
107 pub async fn clear(&self) {
142 if let Err(e) = self.storage.clear().await {
144 warn!("Failed to clear storage: {:?}", e);
145 }
146 }
147
148 pub async fn get_stats(&self) -> ProviderStats {
188 let tenants = self.storage.list_tenants().await.unwrap_or_default();
190 let resource_types = self
191 .storage
192 .list_all_resource_types()
193 .await
194 .unwrap_or_default();
195
196 let mut total_resources = 0;
197
198 for tenant_id in &tenants {
200 for resource_type in &resource_types {
201 let prefix = StorageKey::prefix(tenant_id, resource_type);
202 if let Ok(count) = self.storage.count(prefix).await {
203 total_resources += count;
204 }
205 }
206 }
207
208 ProviderStats {
209 tenant_count: tenants.len(),
210 total_resources,
211 resource_type_count: resource_types.len(),
212 resource_types,
213 }
214 }
215
216 pub async fn list_resources_in_tenant(
218 &self,
219 tenant_id: &str,
220 resource_type: &str,
221 ) -> Vec<Resource> {
222 let prefix = StorageKey::prefix(tenant_id, resource_type);
223 match self.storage.list(prefix, 0, usize::MAX).await {
224 Ok(storage_results) => {
225 let mut resources = Vec::new();
226 for (_key, data) in storage_results {
227 match Resource::from_json(resource_type.to_string(), data) {
228 Ok(resource) => resources.push(resource),
229 Err(e) => {
230 warn!(
231 "Failed to deserialize resource in list_resources_in_tenant: {}",
232 e
233 );
234 }
235 }
236 }
237 resources
238 }
239 Err(e) => {
240 warn!("Storage error in list_resources_in_tenant: {}", e);
241 Vec::new()
242 }
243 }
244 }
245
246 async fn count_resources_for_tenant(&self, tenant_id: &str, resource_type: &str) -> usize {
248 let prefix = StorageKey::prefix(tenant_id, resource_type);
249 match self.storage.count(prefix).await {
250 Ok(count) => count,
251 Err(e) => {
252 warn!("Storage error in count_resources_for_tenant: {}", e);
253 0
254 }
255 }
256 }
257}
258
259impl<S: StorageProvider> ResourceProvider for StandardResourceProvider<S> {
267 type Error = ProviderError;
268
269 async fn create_resource(
270 &self,
271 resource_type: &str,
272 mut data: Value,
273 context: &RequestContext,
274 ) -> Result<VersionedResource, Self::Error> {
275 let tenant_id = self.effective_tenant_id(context);
276
277 info!(
278 "Creating {} resource for tenant '{}' (request: '{}')",
279 resource_type, tenant_id, context.request_id
280 );
281 trace!(
282 "Create data: {}",
283 serde_json::to_string(&data).unwrap_or_else(|_| "invalid json".to_string())
284 );
285
286 context
288 .validate_operation("create")
289 .map_err(|e| ProviderError::Internal { message: e })?;
290
291 if let Some(tenant_context) = &context.tenant_context {
293 if resource_type == "User" {
294 if let Some(max_users) = tenant_context.permissions.max_users {
295 let current_count = self.count_resources_for_tenant(&tenant_id, "User").await;
296 if current_count >= max_users {
297 return Err(ProviderError::Internal {
298 message: format!(
299 "User limit exceeded: {}/{}",
300 current_count, max_users
301 ),
302 });
303 }
304 }
305 } else if resource_type == "Group" {
306 if let Some(max_groups) = tenant_context.permissions.max_groups {
307 let current_count = self.count_resources_for_tenant(&tenant_id, "Group").await;
308 if current_count >= max_groups {
309 return Err(ProviderError::Internal {
310 message: format!(
311 "Group limit exceeded: {}/{}",
312 current_count, max_groups
313 ),
314 });
315 }
316 }
317 }
318 }
319
320 if data.get("id").is_none() {
322 let id = self.generate_tenant_resource_id(&tenant_id, resource_type);
323 if let Some(obj) = data.as_object_mut() {
324 obj.insert("id".to_string(), json!(id));
325 }
326 }
327
328 let resource = Resource::from_json(resource_type.to_string(), data).map_err(|e| {
330 ProviderError::InvalidData {
331 message: format!("Failed to create resource: {}", e),
332 }
333 })?;
334
335 if resource_type == "User" {
337 if let Some(username) = resource.get_username() {
338 self.check_username_duplicate(&tenant_id, username, None)
339 .await?;
340 }
341 }
342
343 let mut resource_with_meta = resource;
345 self.add_creation_metadata(&mut resource_with_meta, "https://example.com/scim/v2")
346 .map_err(|e| ProviderError::Internal {
347 message: format!("Failed to add metadata: {}", e),
348 })?;
349 let resource_id = resource_with_meta.get_id().unwrap_or("unknown").to_string();
350
351 let key = StorageKey::new(&tenant_id, resource_type, &resource_id);
353 let stored_data = self
354 .storage
355 .put(
356 key,
357 resource_with_meta
358 .to_json()
359 .map_err(|e| ProviderError::Internal {
360 message: format!("Failed to serialize resource: {}", e),
361 })?,
362 )
363 .await
364 .map_err(|e| ProviderError::Internal {
365 message: format!("Storage error during create: {}", e),
366 })?;
367
368 let resource =
370 Resource::from_json(resource_type.to_string(), stored_data).map_err(|e| {
371 ProviderError::InvalidData {
372 message: format!("Failed to deserialize stored resource: {}", e),
373 }
374 })?;
375
376 Ok(VersionedResource::new(resource))
377 }
378
379 async fn get_resource(
380 &self,
381 resource_type: &str,
382 id: &str,
383 context: &RequestContext,
384 ) -> Result<Option<VersionedResource>, Self::Error> {
385 let tenant_id = self.effective_tenant_id(context);
386
387 debug!(
388 "Getting {} resource with ID '{}' for tenant '{}' (request: '{}')",
389 resource_type, id, tenant_id, context.request_id
390 );
391
392 context
394 .validate_operation("read")
395 .map_err(|e| ProviderError::Internal { message: e })?;
396
397 let key = StorageKey::new(&tenant_id, resource_type, id);
398 let resource_data = self
399 .storage
400 .get(key)
401 .await
402 .map_err(|e| ProviderError::Internal {
403 message: format!("Storage error during get: {}", e),
404 })?;
405
406 let resource = match resource_data {
407 Some(data) => {
408 let resource =
409 Resource::from_json(resource_type.to_string(), data).map_err(|e| {
410 ProviderError::InvalidData {
411 message: format!("Failed to deserialize resource: {}", e),
412 }
413 })?;
414 trace!("Resource found and returned");
415 Some(VersionedResource::new(resource))
416 }
417 None => {
418 debug!("Resource not found");
419 None
420 }
421 };
422
423 Ok(resource)
424 }
425
426 async fn update_resource(
427 &self,
428 resource_type: &str,
429 id: &str,
430 mut data: Value,
431 expected_version: Option<&RawVersion>,
432 context: &RequestContext,
433 ) -> Result<VersionedResource, Self::Error> {
434 let tenant_id = self.effective_tenant_id(context);
435
436 info!(
437 "Updating {} resource with ID '{}' for tenant '{}' (request: '{}')",
438 resource_type, id, tenant_id, context.request_id
439 );
440 trace!(
441 "Update data: {}",
442 serde_json::to_string(&data).unwrap_or_else(|_| "invalid json".to_string())
443 );
444
445 context
447 .validate_operation("update")
448 .map_err(|e| ProviderError::Internal { message: e })?;
449
450 if let Some(expected_version) = expected_version {
452 let key = StorageKey::new(&tenant_id, resource_type, id);
454 match self.storage.get(key.clone()).await {
455 Ok(Some(current_data)) => {
456 let current_resource =
458 Resource::from_json(resource_type.to_string(), current_data.clone())
459 .map_err(|e| ProviderError::InvalidInput {
460 message: format!("Failed to deserialize stored resource: {}", e),
461 })?;
462
463 let current_version = VersionedResource::new(current_resource.clone())
465 .version()
466 .clone();
467
468 if ¤t_version != expected_version {
469 return Err(ProviderError::PreconditionFailed {
470 message: format!(
471 "Version mismatch: expected {}, got {}",
472 expected_version.as_str(),
473 current_version.as_str()
474 ),
475 });
476 }
477 }
478 Ok(None) => {
479 return Err(ProviderError::NotFound {
480 resource_type: resource_type.to_string(),
481 id: id.to_string(),
482 });
483 }
484 Err(_) => {
485 return Err(ProviderError::Internal {
486 message: "Failed to retrieve resource for version check".to_string(),
487 });
488 }
489 }
490 }
491
492 if let Some(obj) = data.as_object_mut() {
494 obj.insert("id".to_string(), json!(id));
495 }
496
497 let resource = Resource::from_json(resource_type.to_string(), data).map_err(|e| {
499 ProviderError::InvalidData {
500 message: format!("Failed to update resource: {}", e),
501 }
502 })?;
503
504 if resource_type == "User" {
506 if let Some(username) = resource.get_username() {
507 self.check_username_duplicate(&tenant_id, username, Some(id))
508 .await?;
509 }
510 }
511
512 let key = StorageKey::new(&tenant_id, resource_type, id);
514 let exists =
515 self.storage
516 .exists(key.clone())
517 .await
518 .map_err(|e| ProviderError::Internal {
519 message: format!("Storage error during existence check: {}", e),
520 })?;
521
522 if !exists {
523 return Err(ProviderError::ResourceNotFound {
524 resource_type: resource_type.to_string(),
525 id: id.to_string(),
526 tenant_id,
527 });
528 }
529
530 let mut resource_with_meta = resource;
532 self.update_modification_metadata(&mut resource_with_meta)
533 .map_err(|e| ProviderError::Internal {
534 message: format!("Failed to update metadata: {}", e),
535 })?;
536
537 let stored_data = self
539 .storage
540 .put(
541 key,
542 resource_with_meta
543 .to_json()
544 .map_err(|e| ProviderError::Internal {
545 message: format!("Failed to serialize resource: {}", e),
546 })?,
547 )
548 .await
549 .map_err(|e| ProviderError::Internal {
550 message: format!("Storage error during update: {}", e),
551 })?;
552
553 let resource =
555 Resource::from_json(resource_type.to_string(), stored_data).map_err(|e| {
556 ProviderError::InvalidData {
557 message: format!("Failed to deserialize updated resource: {}", e),
558 }
559 })?;
560
561 Ok(VersionedResource::new(resource))
562 }
563
564 async fn delete_resource(
565 &self,
566 resource_type: &str,
567 id: &str,
568 expected_version: Option<&RawVersion>,
569 context: &RequestContext,
570 ) -> Result<(), Self::Error> {
571 let tenant_id = self.effective_tenant_id(context);
572
573 info!(
574 "Deleting {} resource with ID '{}' for tenant '{}' (request: '{}')",
575 resource_type, id, tenant_id, context.request_id
576 );
577
578 context
580 .validate_operation("delete")
581 .map_err(|e| ProviderError::Internal { message: e })?;
582
583 if let Some(expected_version) = expected_version {
585 let key = StorageKey::new(&tenant_id, resource_type, id);
587 match self.storage.get(key.clone()).await {
588 Ok(Some(current_data)) => {
589 let current_resource =
591 Resource::from_json(resource_type.to_string(), current_data.clone())
592 .map_err(|e| ProviderError::InvalidInput {
593 message: format!("Failed to deserialize stored resource: {}", e),
594 })?;
595
596 let current_version = VersionedResource::new(current_resource.clone())
598 .version()
599 .clone();
600
601 if ¤t_version != expected_version {
602 return Err(ProviderError::PreconditionFailed {
603 message: format!(
604 "Version mismatch: expected {}, got {}",
605 expected_version.as_str(),
606 current_version.as_str()
607 ),
608 });
609 }
610 }
611 Ok(None) => {
612 return Err(ProviderError::NotFound {
613 resource_type: resource_type.to_string(),
614 id: id.to_string(),
615 });
616 }
617 Err(_) => {
618 return Err(ProviderError::Internal {
619 message: "Failed to retrieve resource for version check".to_string(),
620 });
621 }
622 }
623 }
624
625 let key = StorageKey::new(&tenant_id, resource_type, id);
627 let removed = self
628 .storage
629 .delete(key)
630 .await
631 .map_err(|e| ProviderError::Internal {
632 message: format!("Storage error during delete: {}", e),
633 })?;
634
635 if !removed {
636 warn!(
637 "Attempted to delete non-existent {} resource with ID '{}' for tenant '{}'",
638 resource_type, id, tenant_id
639 );
640 return Err(ProviderError::ResourceNotFound {
641 resource_type: resource_type.to_string(),
642 id: id.to_string(),
643 tenant_id,
644 });
645 }
646
647 debug!(
648 "Successfully deleted {} resource with ID '{}' for tenant '{}'",
649 resource_type, id, tenant_id
650 );
651 Ok(())
652 }
653
654 async fn list_resources(
655 &self,
656 resource_type: &str,
657 query: Option<&ListQuery>,
658 context: &RequestContext,
659 ) -> Result<Vec<VersionedResource>, Self::Error> {
660 let tenant_id = self.effective_tenant_id(context);
661
662 debug!(
663 "Listing {} resources for tenant '{}' (request: '{}')",
664 resource_type, tenant_id, context.request_id
665 );
666
667 context
669 .validate_operation("list")
670 .map_err(|e| ProviderError::Internal { message: e })?;
671
672 let prefix = StorageKey::prefix(&tenant_id, resource_type);
674 let storage_results = self
675 .storage
676 .list(prefix, 0, usize::MAX) .await
678 .map_err(|e| ProviderError::Internal {
679 message: format!("Storage error during list: {}", e),
680 })?;
681
682 let mut resources = Vec::new();
684 for (_key, data) in storage_results {
685 match Resource::from_json(resource_type.to_string(), data) {
686 Ok(resource) => resources.push(VersionedResource::new(resource)),
687 Err(e) => {
688 warn!("Failed to deserialize resource during list: {}", e);
689 }
691 }
692 }
693
694 let mut filtered_resources = resources;
696
697 if let Some(q) = query {
698 if let Some(start_index) = q.start_index {
700 let start = (start_index.saturating_sub(1)) as usize; if start < filtered_resources.len() {
702 filtered_resources = filtered_resources.into_iter().skip(start).collect();
703 } else {
704 filtered_resources = Vec::new();
705 }
706 }
707
708 if let Some(count) = q.count {
709 filtered_resources.truncate(count as usize);
710 }
711 }
712
713 debug!(
714 "Found {} {} resources for tenant '{}' (after filtering)",
715 filtered_resources.len(),
716 resource_type,
717 tenant_id
718 );
719
720 Ok(filtered_resources)
721 }
722
723 async fn find_resources_by_attribute(
724 &self,
725 resource_type: &str,
726 attribute_name: &str,
727 attribute_value: &str,
728 context: &RequestContext,
729 ) -> Result<Vec<VersionedResource>, Self::Error> {
730 let tenant_id = self.effective_tenant_id(context);
731
732 let prefix = StorageKey::prefix(&tenant_id, resource_type);
734
735 let matches = self
736 .storage
737 .find_by_attribute(prefix, attribute_name, attribute_value)
738 .await
739 .map_err(|e| ProviderError::Internal {
740 message: format!("Storage error during find by attribute: {}", e),
741 })?;
742
743 let mut results = Vec::new();
745 for (_key, data) in matches {
746 match Resource::from_json(resource_type.to_string(), data) {
747 Ok(resource) => results.push(VersionedResource::new(resource)),
748 Err(e) => {
749 warn!("Failed to deserialize resource during find: {}", e);
750 continue;
751 }
752 }
753 }
754
755 Ok(results)
756 }
757
758 async fn patch_resource(
759 &self,
760 resource_type: &str,
761 id: &str,
762 patch_request: &Value,
763 expected_version: Option<&RawVersion>,
764 context: &RequestContext,
765 ) -> Result<VersionedResource, Self::Error> {
766 let tenant_id = self.effective_tenant_id(context);
767
768 if let Some(expected_version) = expected_version {
770 let key = StorageKey::new(&tenant_id, resource_type, id);
772 match self.storage.get(key.clone()).await {
773 Ok(Some(current_data)) => {
774 let current_resource =
776 Resource::from_json(resource_type.to_string(), current_data.clone())
777 .map_err(|e| ProviderError::InvalidInput {
778 message: format!("Failed to deserialize stored resource: {}", e),
779 })?;
780
781 let current_version = VersionedResource::new(current_resource.clone())
783 .version()
784 .clone();
785
786 if ¤t_version != expected_version {
787 return Err(ProviderError::PreconditionFailed {
788 message: format!(
789 "Version mismatch: expected {}, got {}",
790 expected_version.as_str(),
791 current_version.as_str()
792 ),
793 });
794 }
795 }
796 Ok(None) => {
797 return Err(ProviderError::NotFound {
798 resource_type: resource_type.to_string(),
799 id: id.to_string(),
800 });
801 }
802 Err(_) => {
803 return Err(ProviderError::Internal {
804 message: "Failed to retrieve resource for version check".to_string(),
805 });
806 }
807 }
808 }
809
810 let current_resource = self
812 .get_resource(resource_type, id, context)
813 .await?
814 .ok_or_else(|| ProviderError::NotFound {
815 resource_type: resource_type.to_string(),
816 id: id.to_string(),
817 })?;
818
819 let mut resource_data =
821 current_resource
822 .resource()
823 .to_json()
824 .map_err(|e| ProviderError::Internal {
825 message: format!("Failed to serialize resource for patching: {}", e),
826 })?;
827
828 if let Some(operations) = patch_request.get("Operations") {
830 if let Some(ops_array) = operations.as_array() {
831 for operation in ops_array {
832 self.apply_patch_operation(&mut resource_data, operation)?;
833 }
834 }
835 }
836
837 let patched_resource = Resource::from_json(resource_type.to_string(), resource_data)
839 .map_err(|e| ProviderError::InvalidData {
840 message: format!("Failed to create patched resource: {}", e),
841 })?;
842
843 let key = StorageKey::new(&tenant_id, resource_type, id);
845 let patched_json = patched_resource
846 .to_json()
847 .map_err(|e| ProviderError::Internal {
848 message: format!("Failed to serialize patched resource: {}", e),
849 })?;
850
851 self.storage
852 .put(key, patched_json)
853 .await
854 .map_err(|e| ProviderError::Internal {
855 message: format!("Storage error during patch: {}", e),
856 })?;
857
858 Ok(VersionedResource::new(patched_resource))
859 }
860
861 async fn resource_exists(
862 &self,
863 resource_type: &str,
864 id: &str,
865 context: &RequestContext,
866 ) -> Result<bool, Self::Error> {
867 let tenant_id = self.effective_tenant_id(context);
868
869 let key = StorageKey::new(&tenant_id, resource_type, id);
870 self.storage
871 .exists(key)
872 .await
873 .map_err(|e| ProviderError::Internal {
874 message: format!("Storage error during exists check: {}", e),
875 })
876 }
877}