wami 0.16.0

Who Am I - Multicloud Identity, IAM, STS, and SSO operations library for Rust
Documentation
//! Attribute-Based Access Control (ABAC)
//!
//! This example demonstrates:
//! - Tagging resources with attributes
//! - Creating tag-based policies
//! - Dynamic access control based on attributes
//!
//! Scenario: Access control based on department and project tags.
//!
//! Run with: `cargo run --example 17_attribute_based_access_control`

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()));

    // Create context
    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());

    // === CREATE TAGGED USERS ===
    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)");

    // === CREATE ABAC POLICY ===
    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(())
}