Skip to main content

TenantPath

Struct TenantPath 

Source
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

Source

pub fn new(segments: Vec<u64>) -> TenantPath

Creates a new tenant path from numeric segments.

Source

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
Hide additional 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}
Source

pub fn from_segments<I>(segments: I) -> TenantPath
where I: Into<Vec<u64>>,

Creates a tenant path from an iterator of numeric segments.

Source

pub fn as_string(&self) -> String

Returns the full path as a string joined by ‘/’.

Source

pub fn root(&self) -> Option<String>

Returns the root (first) tenant ID as a string.

Source

pub fn leaf(&self) -> Option<String>

Returns the leaf (last) tenant ID as a string.

Source

pub fn root_u64(&self) -> Option<u64>

Returns the root (first) tenant ID as u64.

Source

pub fn leaf_u64(&self) -> Option<u64>

Returns the leaf (last) tenant ID as u64.

Source

pub fn depth(&self) -> usize

Returns the depth of the tenant hierarchy.

Source

pub fn starts_with(&self, other: &TenantPath) -> bool

Check if this tenant path starts with another tenant path (is a child or same)

Source

pub fn is_descendant_of(&self, other: &TenantPath) -> bool

Returns true if this path is a descendant of the given path.

Source

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

Source§

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)

Performs copy-assignment from source. Read more
Source§

impl Debug for TenantPath

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error>

Formats the value using the given formatter. Read more
Source§

impl<'de> Deserialize<'de> for TenantPath

Source§

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

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error>

Formats the value using the given formatter. Read more
Source§

impl Eq for TenantPath

Source§

impl Hash for TenantPath

Source§

fn hash<__H>(&self, state: &mut __H)
where __H: Hasher,

Feeds this value into the given Hasher. Read more
1.3.0 · Source§

fn hash_slice<H>(data: &[Self], state: &mut H)
where H: Hasher, Self: Sized,

Feeds a slice of this type into the given Hasher. Read more
Source§

impl PartialEq for TenantPath

Source§

fn eq(&self, other: &TenantPath) -> bool

Equality operator ==. Read more
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Inequality operator !=. Read more
Source§

impl Serialize for TenantPath

Source§

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
Source§

impl StructuralPartialEq for TenantPath

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> DeserializeOwned for T
where T: for<'de> Deserialize<'de>,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T> ToString for T
where T: Display + ?Sized,

Source§

fn to_string(&self) -> String

Converts the given value to a String. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V