use std::sync::Arc;
use tokio::sync::RwLock;
use wami::arn::{TenantPath, WamiArn};
use wami::context::WamiContext;
use wami::service::{PolicyService, UserService};
use wami::store::memory::InMemoryWamiStore;
use wami::types::Tag;
use wami::wami::identity::user::requests::CreateUserRequest;
use wami::wami::policies::policy::requests::CreatePolicyRequest;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("=== Attribute-Based Access Control (ABAC) ===\n");
let store = Arc::new(RwLock::new(InMemoryWamiStore::default()));
let context = WamiContext::builder()
.instance_id("123456789012")
.tenant_path(TenantPath::single(0))
.caller_arn(
WamiArn::builder()
.service(wami::arn::Service::Iam)
.tenant_path(TenantPath::single(0))
.wami_instance("123456789012")
.resource("user", "admin")
.build()?,
)
.is_root(false)
.build()?;
let user_service = UserService::new(store.clone());
let policy_service = PolicyService::new(store.clone());
println!("Step 1: Creating users with department/project tags...\n");
user_service
.create_user(
&context,
CreateUserRequest {
user_name: "alice".to_string(),
path: Some("/".to_string()),
permissions_boundary: None,
tags: Some(vec![
Tag {
key: "Department".to_string(),
value: "Engineering".to_string(),
},
Tag {
key: "Project".to_string(),
value: "ProjectA".to_string(),
},
]),
},
)
.await?;
println!("✓ Created alice (Engineering, ProjectA)");
user_service
.create_user(
&context,
CreateUserRequest {
user_name: "bob".to_string(),
path: Some("/".to_string()),
permissions_boundary: None,
tags: Some(vec![
Tag {
key: "Department".to_string(),
value: "Engineering".to_string(),
},
Tag {
key: "Project".to_string(),
value: "ProjectB".to_string(),
},
]),
},
)
.await?;
println!("✓ Created bob (Engineering, ProjectB)");
user_service
.create_user(
&context,
CreateUserRequest {
user_name: "charlie".to_string(),
path: Some("/".to_string()),
permissions_boundary: None,
tags: Some(vec![
Tag {
key: "Department".to_string(),
value: "Sales".to_string(),
},
Tag {
key: "Project".to_string(),
value: "ProjectC".to_string(),
},
]),
},
)
.await?;
println!("✓ Created charlie (Sales, ProjectC)");
println!("\n\nStep 2: Creating ABAC policy...\n");
let abac_policy_doc = r#"{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Action": "s3:*",
"Resource": "arn:aws:s3:::${aws:PrincipalTag/Project}/*",
"Condition": {
"StringEquals": {
"s3:ExistingObjectTag/Department": "${aws:PrincipalTag/Department}"
}
}
}]
}"#;
policy_service
.create_policy(
&context,
CreatePolicyRequest {
policy_name: "ABACPolicy".to_string(),
path: Some("/abac/".to_string()),
policy_document: abac_policy_doc.to_string(),
description: Some("ABAC policy using tags".to_string()),
tags: None,
},
)
.await?;
println!("✓ Created ABAC policy with tag-based conditions");
println!(" - Resource access based on PrincipalTag/Project");
println!(" - Object access requires matching Department tag");
println!("\n\n✅ Example completed successfully!");
println!("Key takeaways:");
println!("- ABAC uses tags for dynamic access control");
println!("- Policies reference ${{aws:PrincipalTag/Key}}");
println!("- Scales better than RBAC for large organizations");
Ok(())
}