pub struct TenantPath {
pub segments: Vec<u64>,
}Expand description
Represents a hierarchical tenant path.
Tenants can be organized in a hierarchy using opaque numeric IDs.
The path is represented as a vector of numeric tenant ID segments.
Uses / separator to align with AWS ARN conventions.
Fields§
§segments: Vec<u64>Ordered segments of the tenant hierarchy (e.g., [12345678, 87654321, 99999999])
Implementations§
Source§impl TenantPath
impl TenantPath
Sourcepub fn new(segments: Vec<u64>) -> TenantPath
pub fn new(segments: Vec<u64>) -> TenantPath
Creates a new tenant path from numeric segments.
Sourcepub fn single(tenant_id: u64) -> TenantPath
pub fn single(tenant_id: u64) -> TenantPath
Creates a tenant path from a single numeric tenant ID.
Examples found in repository?
examples/18_session_tokens.rs (line 30)
22async fn main() -> Result<(), Box<dyn std::error::Error>> {
23 println!("=== Session Tokens ===\n");
24
25 let store = Arc::new(RwLock::new(InMemoryWamiStore::default()));
26
27 // Create context
28 let context = WamiContext::builder()
29 .instance_id("123456789012")
30 .tenant_path(TenantPath::single(0))
31 .caller_arn(
32 WamiArn::builder()
33 .service(wami::arn::Service::Iam)
34 .tenant_path(TenantPath::single(0))
35 .wami_instance("123456789012")
36 .resource("user", "admin")
37 .build()?,
38 )
39 .is_root(false)
40 .build()?;
41
42 // Create user
43 let user_service = UserService::new(store.clone());
44 let alice_req = CreateUserRequest {
45 user_name: "alice".to_string(),
46 path: Some("/".to_string()),
47 permissions_boundary: None,
48 tags: None,
49 };
50 let alice = user_service.create_user(&context, alice_req).await?;
51 println!("Step 1: Created user alice");
52 println!(" ARN: {}\n", alice.arn);
53
54 // Generate session token
55 let sts_service = SessionTokenService::new(store.clone());
56
57 let token_req = GetSessionTokenRequest {
58 duration_seconds: Some(3600),
59 serial_number: None,
60 token_code: None,
61 };
62
63 let response = sts_service
64 .get_session_token(&context, token_req, &alice.arn)
65 .await?;
66
67 println!("Step 2: Generated session token");
68 println!(" Access Key: {}", response.credentials.access_key_id);
69 println!(
70 " Secret Key: {}...",
71 &response.credentials.secret_access_key[..20]
72 );
73 println!(
74 " Session Token: {}...",
75 &response.credentials.session_token[..30]
76 );
77 println!(" Expiration: {}", response.credentials.expiration);
78
79 println!("\n✅ Example completed successfully!");
80 println!("Key takeaways:");
81 println!("- Session tokens provide temporary credentials");
82 println!("- Credentials expire after specified duration");
83 println!("- Useful for temporary or delegated access");
84
85 Ok(())
86}More examples
examples/20_federated_access.rs (line 30)
22async fn main() -> Result<(), Box<dyn std::error::Error>> {
23 println!("=== Federated Access ===\n");
24
25 let store = Arc::new(RwLock::new(InMemoryWamiStore::default()));
26
27 // Create context
28 let context = WamiContext::builder()
29 .instance_id("123456789012")
30 .tenant_path(TenantPath::single(0))
31 .caller_arn(
32 WamiArn::builder()
33 .service(wami::arn::Service::Iam)
34 .tenant_path(TenantPath::single(0))
35 .wami_instance("123456789012")
36 .resource("user", "admin")
37 .build()?,
38 )
39 .is_root(false)
40 .build()?;
41
42 // Create admin user who will generate federation tokens
43 let user_service = UserService::new(store.clone());
44 let admin = user_service
45 .create_user(
46 &context,
47 CreateUserRequest {
48 user_name: "admin".to_string(),
49 path: Some("/".to_string()),
50 permissions_boundary: None,
51 tags: None,
52 },
53 )
54 .await?;
55
56 let fed_service = FederationService::new(store.clone());
57
58 println!("Step 1: Generating federation token for external user...\n");
59
60 let fed_req = GetFederationTokenRequest {
61 name: "partner-user".to_string(),
62 duration_seconds: Some(3600),
63 policy: Some(r#"{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":"s3:GetObject","Resource":"*"}]}"#.to_string()),
64 };
65
66 let response = fed_service
67 .get_federation_token(&context, fed_req, &admin.arn)
68 .await?;
69
70 println!("✓ Generated federation token:");
71 println!(" Federated User ARN: {}", response.federated_user.arn);
72 println!(" Access Key: {}", response.credentials.access_key_id);
73 println!(" Expiration: {}", response.credentials.expiration);
74
75 println!("\n✅ Example completed successfully!");
76 println!("Key takeaways:");
77 println!("- Federation enables external user access");
78 println!("- Temporary credentials with limited permissions");
79 println!("- Useful for partner integrations");
80
81 Ok(())
82}examples/01_hello_wami.rs (line 31)
19async fn main() -> Result<(), Box<dyn std::error::Error>> {
20 println!("=== Hello WAMI ===\n");
21
22 // Step 1: Initialize the store
23 println!("Step 1: Initializing in-memory store...");
24 let mut store = InMemoryWamiStore::default();
25 println!("✓ Store initialized");
26
27 // Step 2: Create a WamiContext for operations
28 println!("\nStep 2: Creating WAMI context...");
29 let context = WamiContext::builder()
30 .instance_id("123456789012")
31 .tenant_path(TenantPath::single(0)) // Root tenant ID is 0
32 .caller_arn(
33 WamiArn::builder()
34 .service(wami::arn::Service::Iam)
35 .tenant_path(TenantPath::single(0))
36 .wami_instance("123456789012")
37 .resource("user", "admin")
38 .build()?,
39 )
40 .is_root(false)
41 .build()?;
42 println!("✓ Context created");
43
44 // Step 3: Build a user using pure functions
45 println!("\nStep 3: Building user 'alice'...");
46 let user = build_user("alice".to_string(), Some("/".to_string()), &context)?;
47 println!("✓ User built with ARN: {}", user.wami_arn);
48
49 // Step 4: Store the user
50 println!("\nStep 4: Storing user in the store...");
51 let created_user = store.create_user(user).await?;
52 println!("✓ User stored successfully");
53 println!(" - Name: {}", created_user.user_name);
54 println!(" - User ID: {}", created_user.user_id);
55 println!(" - ARN: {}", created_user.wami_arn);
56
57 // Step 5: Retrieve the user
58 println!("\nStep 5: Retrieving user from store...");
59 let retrieved = store.get_user("alice").await?;
60 match retrieved {
61 Some(user) => {
62 println!("✓ User retrieved successfully");
63 println!(" - Name: {}", user.user_name);
64 println!(" - Path: {}", user.path);
65 }
66 None => println!("✗ User not found"),
67 }
68
69 println!("\n✅ Example completed successfully!");
70 println!("Key takeaways:");
71 println!("- InMemoryWamiStore provides a simple storage backend");
72 println!("- Providers (AWS, GCP, Azure) handle platform-specific details");
73 println!("- Pure functions create domain objects without side effects");
74
75 Ok(())
76}examples/15_policy_evaluation_simulation.rs (line 30)
22async fn main() -> Result<(), Box<dyn std::error::Error>> {
23 println!("=== Policy Evaluation Simulation ===\n");
24
25 let store = Arc::new(RwLock::new(InMemoryWamiStore::default()));
26
27 // Create context
28 let context = WamiContext::builder()
29 .instance_id("123456789012")
30 .tenant_path(TenantPath::single(0))
31 .caller_arn(
32 WamiArn::builder()
33 .service(wami::arn::Service::Iam)
34 .tenant_path(TenantPath::single(0))
35 .wami_instance("123456789012")
36 .resource("user", "admin")
37 .build()?,
38 )
39 .is_root(false)
40 .build()?;
41
42 let eval_service = EvaluationService::new(store.clone(), "123456789012".to_string());
43 let user_service = UserService::new(store.clone());
44
45 // Create user
46 println!("Step 1: Creating user...\n");
47 let req = CreateUserRequest {
48 user_name: "alice".to_string(),
49 path: Some("/".to_string()),
50 permissions_boundary: None,
51 tags: None,
52 };
53 let alice = user_service.create_user(&context, req).await?;
54 println!("✓ Created alice: {}", alice.arn);
55
56 // === SIMULATE POLICY ===
57 println!("\n\nStep 2: Simulating custom policy...\n");
58
59 let policy_doc = r#"{
60 "Version": "2012-10-17",
61 "Statement": [{
62 "Effect": "Allow",
63 "Action": ["s3:GetObject", "s3:PutObject"],
64 "Resource": "arn:aws:s3:::my-bucket/*"
65 }]
66}"#;
67
68 // Test allowed action
69 let sim_req = SimulateCustomPolicyRequest {
70 policy_input_list: vec![policy_doc.to_string()],
71 action_names: vec!["s3:GetObject".to_string()],
72 resource_arns: Some(vec!["arn:aws:s3:::my-bucket/file.txt".to_string()]),
73 context_entries: None,
74 };
75
76 let result = eval_service.simulate_custom_policy(sim_req).await?;
77 println!("✓ Simulation: s3:GetObject on my-bucket/file.txt");
78 println!(" Decision: {}", result.evaluation_results[0].eval_decision);
79
80 // Test denied action
81 let denied_req = SimulateCustomPolicyRequest {
82 policy_input_list: vec![policy_doc.to_string()],
83 action_names: vec!["s3:DeleteObject".to_string()],
84 resource_arns: Some(vec!["arn:aws:s3:::my-bucket/file.txt".to_string()]),
85 context_entries: None,
86 };
87
88 let denied_result = eval_service.simulate_custom_policy(denied_req).await?;
89 println!("\n✓ Simulation: s3:DeleteObject on my-bucket/file.txt");
90 println!(
91 " Decision: {}",
92 denied_result.evaluation_results[0].eval_decision
93 );
94
95 println!("\n✅ Example completed successfully!");
96 println!("Key takeaways:");
97 println!("- Policy simulation helps test before deployment");
98 println!("- Simulate custom policies or principal policies");
99 println!("- Understand allow/deny decisions");
100 println!("- Identify missing permissions");
101
102 Ok(())
103}examples/19_role_assumption_workflow.rs (line 31)
23async fn main() -> Result<(), Box<dyn std::error::Error>> {
24 println!("=== Role Assumption Workflow ===\n");
25
26 let store = Arc::new(RwLock::new(InMemoryWamiStore::default()));
27
28 // Create context
29 let context = WamiContext::builder()
30 .instance_id("123456789012")
31 .tenant_path(TenantPath::single(0))
32 .caller_arn(
33 WamiArn::builder()
34 .service(wami::arn::Service::Iam)
35 .tenant_path(TenantPath::single(0))
36 .wami_instance("123456789012")
37 .resource("user", "admin")
38 .build()?,
39 )
40 .is_root(false)
41 .build()?;
42
43 let user_service = UserService::new(store.clone());
44 let role_service = RoleService::new(store.clone());
45 let sts_service = AssumeRoleService::new(store.clone());
46
47 // Create user
48 println!("Step 1: Creating user...\n");
49 let alice = user_service
50 .create_user(
51 &context,
52 CreateUserRequest {
53 user_name: "alice".to_string(),
54 path: Some("/".to_string()),
55 permissions_boundary: None,
56 tags: None,
57 },
58 )
59 .await?;
60 println!("✓ Created alice: {}", alice.arn);
61
62 // Create elevated role
63 println!("\nStep 2: Creating admin role...\n");
64 let trust_policy = r#"{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":{"AWS":"*"},"Action":"sts:AssumeRole"}]}"#;
65 let role = role_service
66 .create_role(
67 &context,
68 CreateRoleRequest {
69 role_name: "AdminRole".to_string(),
70 path: Some("/".to_string()),
71 assume_role_policy_document: trust_policy.to_string(),
72 description: Some("Admin role for elevated access".to_string()),
73 max_session_duration: Some(3600),
74 permissions_boundary: None,
75 tags: None,
76 },
77 )
78 .await?;
79 println!("✓ Created AdminRole: {}", role.arn);
80
81 // Assume role
82 println!("\nStep 3: Alice assuming AdminRole...\n");
83 let assume_req = AssumeRoleRequest {
84 role_arn: role.arn.clone(),
85 role_session_name: "alice-admin-session".to_string(),
86 duration_seconds: Some(3600),
87 external_id: None,
88 policy: None,
89 };
90
91 let response = sts_service
92 .assume_role(&context, assume_req, &alice.arn)
93 .await?;
94 println!("✓ Successfully assumed role!");
95 println!(" Assumed Role ARN: {}", response.assumed_role_user.arn);
96 println!(" Access Key: {}", response.credentials.access_key_id);
97 println!(" Expiration: {}", response.credentials.expiration);
98
99 println!("\n✅ Example completed successfully!");
100 println!("Key takeaways:");
101 println!("- AssumeRole provides temporary elevated permissions");
102 println!("- Trust policies control who can assume roles");
103 println!("- Session credentials expire automatically");
104
105 Ok(())
106}examples/09_multi_cloud_user_sync.rs (line 29)
21async fn main() -> Result<(), Box<dyn std::error::Error>> {
22 println!("=== Multi-Cloud User Sync ===\n");
23
24 let store = Arc::new(RwLock::new(InMemoryWamiStore::default()));
25
26 // Create context for operations
27 let context = WamiContext::builder()
28 .instance_id("123456789012")
29 .tenant_path(TenantPath::single(0))
30 .caller_arn(
31 WamiArn::builder()
32 .service(wami::arn::Service::Iam)
33 .tenant_path(TenantPath::single(0))
34 .wami_instance("123456789012")
35 .resource("user", "admin")
36 .build()?,
37 )
38 .is_root(false)
39 .build()?;
40
41 println!("✓ Using unified context for all operations");
42
43 // === CREATE USER ===
44 println!("\n\nStep 1: Creating alice user...\n");
45
46 let user_service = UserService::new(store.clone());
47
48 let user_req = CreateUserRequest {
49 user_name: "alice".to_string(),
50 path: Some("/cloud-sync/".to_string()),
51 permissions_boundary: None,
52 tags: Some(vec![
53 wami::types::Tag {
54 key: "Email".to_string(),
55 value: "alice@company.com".to_string(),
56 },
57 wami::types::Tag {
58 key: "MultiCloud".to_string(),
59 value: "true".to_string(),
60 },
61 ]),
62 };
63
64 let user = user_service.create_user(&context, user_req).await?;
65 println!("✓ Created alice:");
66 println!(" - ARN: {}", user.arn);
67 println!(" - User ID: {}", user.user_id);
68 println!(" - WAMI ARN: {}", user.wami_arn);
69
70 // === COMPARE ARN FORMATS ===
71 println!("\n\nStep 2: Understanding WAMI ARN format...\n");
72
73 println!("WAMI unified ARN:");
74 println!(" {}", user.wami_arn);
75 println!("\nThis ARN can be transformed to provider-specific formats:");
76 println!(" - AWS ARN format for AWS API calls");
77 println!(" - GCP resource name format for GCP API calls");
78 println!(" - Azure resource ID format for Azure API calls");
79
80 // === DEMONSTRATE PROVIDER METADATA ===
81 println!("\n\nStep 3: Understanding WAMI architecture...\n");
82
83 println!("WAMI provides:");
84 println!("- Unified WAMI ARN format (for internal operations)");
85 println!("- Provider-specific ARN transformation when needed");
86 println!("- Consistent resource identification across clouds");
87 println!("- Tags for categorization and metadata");
88
89 println!("\nBenefits:");
90 println!("- Unified identity management across clouds");
91 println!("- Provider-agnostic operations with context");
92 println!("- Cross-cloud audit trails with WAMI ARNs");
93 println!("- Multi-cloud resource tracking");
94
95 println!("\n✅ Example completed successfully!");
96 println!("Key takeaways:");
97 println!("- WAMI uses a unified ARN format internally");
98 println!("- Provider-specific ARNs can be generated when needed");
99 println!("- Context-based operations work across all providers");
100 println!("- Use tags to track cross-cloud relationships");
101
102 Ok(())
103}Additional examples can be found in:
- examples/10_provider_switching.rs
- examples/17_attribute_based_access_control.rs
- examples/02_basic_crud_operations.rs
- examples/03_service_layer_intro.rs
- examples/05_tenant_hierarchy.rs
- examples/24_policy_attachment.rs
- examples/06_tenant_quotas_and_limits.rs
- examples/14_policy_basics.rs
- examples/11_hybrid_cloud_setup.rs
- examples/07_cross_tenant_role_assumption.rs
- examples/16_role_based_access_control.rs
- examples/12_provider_specific_features.rs
- examples/04_simple_multi_tenant.rs
- examples/08_tenant_migration.rs
- examples/13_disaster_recovery_multi_cloud.rs
- examples/23_permissions_boundaries.rs
- examples/22_identity_providers_federation.rs
Sourcepub fn from_segments<I>(segments: I) -> TenantPath
pub fn from_segments<I>(segments: I) -> TenantPath
Creates a tenant path from an iterator of numeric segments.
Sourcepub fn starts_with(&self, other: &TenantPath) -> bool
pub fn starts_with(&self, other: &TenantPath) -> bool
Check if this tenant path starts with another tenant path (is a child or same)
Sourcepub fn is_descendant_of(&self, other: &TenantPath) -> bool
pub fn is_descendant_of(&self, other: &TenantPath) -> bool
Returns true if this path is a descendant of the given path.
Sourcepub fn is_ancestor_of(&self, other: &TenantPath) -> bool
pub fn is_ancestor_of(&self, other: &TenantPath) -> bool
Returns true if this path is an ancestor of the given path.
Trait Implementations§
Source§impl Clone for TenantPath
impl Clone for TenantPath
Source§fn clone(&self) -> TenantPath
fn clone(&self) -> TenantPath
Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
Performs copy-assignment from
source. Read moreSource§impl Debug for TenantPath
impl Debug for TenantPath
Source§impl<'de> Deserialize<'de> for TenantPath
impl<'de> Deserialize<'de> for TenantPath
Source§fn deserialize<D>(
deserializer: D,
) -> Result<TenantPath, <D as Deserializer<'de>>::Error>where
D: Deserializer<'de>,
fn deserialize<D>(
deserializer: D,
) -> Result<TenantPath, <D as Deserializer<'de>>::Error>where
D: Deserializer<'de>,
Deserialize this value from the given Serde deserializer. Read more
Source§impl Display for TenantPath
impl Display for TenantPath
impl Eq for TenantPath
Source§impl Hash for TenantPath
impl Hash for TenantPath
Source§impl PartialEq for TenantPath
impl PartialEq for TenantPath
Source§impl Serialize for TenantPath
impl Serialize for TenantPath
Source§fn serialize<S>(
&self,
serializer: S,
) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error>where
S: Serializer,
fn serialize<S>(
&self,
serializer: S,
) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error>where
S: Serializer,
Serialize this value into the given Serde serializer. Read more
impl StructuralPartialEq for TenantPath
Auto Trait Implementations§
impl Freeze for TenantPath
impl RefUnwindSafe for TenantPath
impl Send for TenantPath
impl Sync for TenantPath
impl Unpin for TenantPath
impl UnsafeUnpin for TenantPath
impl UnwindSafe for TenantPath
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more