use scim_server::{
ScimServer,
multi_tenant::ScimOperation,
operation_handler::{ScimOperationHandler, ScimOperationRequest},
providers::StandardResourceProvider,
resource::TenantContext,
resource_handlers::create_user_resource_handler,
storage::InMemoryStorage,
};
use serde_json::json;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
env_logger::init();
println!("๐ SCIM Operation Handler Example");
println!("==================================\n");
let storage = InMemoryStorage::new();
let provider = StandardResourceProvider::new(storage);
let mut server = ScimServer::new(provider)?;
let user_schema = server
.get_schema_by_id("urn:ietf:params:scim:schemas:core:2.0:User")
.expect("User schema should be available")
.clone();
let user_handler = create_user_resource_handler(user_schema);
server.register_resource_type(
"User",
user_handler,
vec![
ScimOperation::Create,
ScimOperation::Read,
ScimOperation::Update,
ScimOperation::Delete,
ScimOperation::List,
ScimOperation::Search,
],
)?;
let handler = ScimOperationHandler::new(server);
println!("โ
Server initialized with operation handler\n");
println!("๐ SCHEMA OPERATIONS");
println!("==================");
let schemas_request = ScimOperationRequest::get_schemas();
let schemas_response = handler.handle_operation(schemas_request).await;
if schemas_response.success {
println!("โ
Retrieved schemas successfully");
if let Some(data) = schemas_response.data {
if let Some(schemas_array) = data.get("schemas") {
println!(
" Found {} schemas",
schemas_array.as_array().unwrap().len()
);
}
}
} else {
println!(
"โ Failed to retrieve schemas: {:?}",
schemas_response.error
);
}
let user_schema_request =
ScimOperationRequest::get_schema("urn:ietf:params:scim:schemas:core:2.0:User");
let user_schema_response = handler.handle_operation(user_schema_request).await;
if user_schema_response.success {
println!("โ
Retrieved User schema successfully");
if let Some(data) = user_schema_response.data {
if let Some(attributes) = data.get("attributes") {
println!(
" User schema has {} attributes",
attributes.as_array().unwrap().len()
);
}
}
}
println!();
println!("๐ค USER MANAGEMENT OPERATIONS");
println!("============================");
let create_request = ScimOperationRequest::create(
"User",
json!({
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
"userName": "alice.doe",
"name": {
"familyName": "Doe",
"givenName": "Alice",
"formatted": "Alice Doe"
},
"emails": [
{
"value": "alice.doe@example.com",
"type": "work",
"primary": true
}
],
"active": true
}),
);
let create_response = handler.handle_operation(create_request).await;
let user_id = if create_response.success {
let user_id = create_response.metadata.resource_id.clone().unwrap();
println!("โ
Created user with ID: {}", user_id);
user_id
} else {
println!("โ Failed to create user: {:?}", create_response.error);
return Ok(());
};
let get_request = ScimOperationRequest::get("User", &user_id);
let get_response = handler.handle_operation(get_request).await;
if get_response.success {
println!("โ
Retrieved user successfully");
if let Some(data) = get_response.data {
if let Some(username) = data.get("userName") {
println!(" Username: {}", username.as_str().unwrap());
}
}
} else {
println!("โ Failed to retrieve user: {:?}", get_response.error);
}
let update_request = ScimOperationRequest::update(
"User",
&user_id,
json!({
"id": user_id,
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
"userName": "alice.doe",
"name": {
"familyName": "Doe",
"givenName": "Alice",
"formatted": "Alice M. Doe"
},
"emails": [
{
"value": "alice.doe@newcompany.com",
"type": "work",
"primary": true
}
],
"active": true
}),
);
let update_response = handler.handle_operation(update_request).await;
if update_response.success {
println!("โ
Updated user successfully");
} else {
println!("โ Failed to update user: {:?}", update_response.error);
}
let search_request = ScimOperationRequest::search("User", "userName", json!("alice.doe"));
let search_response = handler.handle_operation(search_request).await;
if search_response.success {
if search_response.data.is_some() {
println!("โ
Found user by username search");
} else {
println!("โ ๏ธ No user found matching search criteria");
}
} else {
println!("โ Search failed: {:?}", search_response.error);
}
let exists_request = ScimOperationRequest::exists("User", &user_id);
let exists_response = handler.handle_operation(exists_request).await;
if exists_response.success {
if let Some(data) = exists_response.data {
if let Some(exists) = data.get("exists") {
println!("โ
User exists check: {}", exists.as_bool().unwrap());
}
}
}
let list_request = ScimOperationRequest::list("User");
let list_response = handler.handle_operation(list_request).await;
if list_response.success {
println!("โ
Listed users successfully");
println!(
" Total users: {}",
list_response.metadata.resource_count.unwrap_or(0)
);
} else {
println!("โ Failed to list users: {:?}", list_response.error);
}
println!();
println!("๐ข MULTI-TENANT OPERATIONS");
println!("=========================");
let tenant_a_context = TenantContext::new("tenant-a".to_string(), "client-a".to_string());
let tenant_create_request = ScimOperationRequest::create(
"User",
json!({
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
"userName": "bob.smith",
"name": {
"familyName": "Smith",
"givenName": "Bob"
}
}),
)
.with_tenant(tenant_a_context);
let tenant_create_response = handler.handle_operation(tenant_create_request).await;
if tenant_create_response.success {
println!("โ
Created user in tenant A");
println!(
" Tenant ID: {}",
tenant_create_response.metadata.tenant_id.unwrap()
);
}
let global_list_request = ScimOperationRequest::list("User");
let global_list_response = handler.handle_operation(global_list_request).await;
let tenant_a_context = TenantContext::new("tenant-a".to_string(), "client-a".to_string());
let tenant_list_request = ScimOperationRequest::list("User").with_tenant(tenant_a_context);
let tenant_list_response = handler.handle_operation(tenant_list_request).await;
if global_list_response.success && tenant_list_response.success {
println!("โ
Tenant isolation verified:");
println!(
" Global users: {}",
global_list_response.metadata.resource_count.unwrap_or(0)
);
println!(
" Tenant A users: {}",
tenant_list_response.metadata.resource_count.unwrap_or(0)
);
}
println!();
println!("โ ๏ธ ERROR HANDLING DEMONSTRATION");
println!("===============================");
let invalid_get_request = ScimOperationRequest::get("User", "non-existent-id");
let invalid_get_response = handler.handle_operation(invalid_get_request).await;
if !invalid_get_response.success {
println!("โ
Properly handled non-existent resource error");
println!(" Error: {}", invalid_get_response.error.unwrap());
println!(
" Error Code: {}",
invalid_get_response.error_code.unwrap()
);
}
let invalid_create_request = ScimOperationRequest::create(
"User",
json!({
"invalid_field": "invalid_value"
}),
);
let invalid_create_response = handler.handle_operation(invalid_create_request).await;
if !invalid_create_response.success {
println!("โ
Properly handled validation error");
println!(
" Error Code: {}",
invalid_create_response.error_code.unwrap()
);
}
let unsupported_request = ScimOperationRequest::get("UnsupportedType", "some-id");
let unsupported_response = handler.handle_operation(unsupported_request).await;
if !unsupported_response.success {
println!("โ
Properly handled unsupported resource type");
println!(
" Error Code: {}",
unsupported_response.error_code.unwrap()
);
}
println!();
println!("๐งน CLEANUP");
println!("=========");
let delete_request = ScimOperationRequest::delete("User", &user_id);
let delete_response = handler.handle_operation(delete_request).await;
if delete_response.success {
println!("โ
Deleted user successfully");
} else {
println!("โ Failed to delete user: {:?}", delete_response.error);
}
let verify_request = ScimOperationRequest::get("User", &user_id);
let verify_response = handler.handle_operation(verify_request).await;
if !verify_response.success {
println!("โ
Verified user deletion - user no longer exists");
}
println!();
println!("๐ OPERATION HANDLER EXAMPLE COMPLETED!");
println!("=======================================");
println!("โ
Demonstrated structured SCIM operations");
println!("โ
Showed framework-agnostic request/response handling");
println!("โ
Verified multi-tenant support");
println!("โ
Tested comprehensive error handling");
println!("โ
Confirmed resource lifecycle management");
println!();
println!("๐ง INTEGRATION READY:");
println!(" โข Use ScimOperationHandler for HTTP frameworks (Axum, Actix, etc.)");
println!(" โข Use ScimOperationHandler for MCP tool integration");
println!(" โข Use ScimOperationHandler for CLI tools");
println!(" โข Use ScimOperationHandler for any custom integration");
Ok(())
}