1use std::sync::Arc;
13use tokio::sync::RwLock;
14use wami::error::Result;
15use wami::provider::{AwsProvider, CloudProvider, ResourceLimits, ResourceType};
16use wami::service::UserService;
17use wami::store::memory::InMemoryWamiStore;
18use wami::wami::identity::user::requests::{CreateUserRequest, ListUsersRequest};
19
20#[derive(Debug, Clone)]
22struct OnPremiseProvider {
23 #[allow(dead_code)]
24 datacenter_id: String,
25 limits: ResourceLimits,
26}
27
28impl OnPremiseProvider {
29 fn new(datacenter_id: String) -> Self {
30 Self {
31 datacenter_id,
32 limits: ResourceLimits::default(),
33 }
34 }
35}
36
37impl CloudProvider for OnPremiseProvider {
38 fn name(&self) -> &str {
39 "onpremise"
40 }
41
42 fn generate_resource_identifier(
43 &self,
44 resource_type: ResourceType,
45 account_id: &str,
46 path: &str,
47 name: &str,
48 ) -> String {
49 let resource_name = match resource_type {
50 ResourceType::User => "user",
51 ResourceType::Group => "group",
52 ResourceType::Role => "role",
53 ResourceType::Policy => "policy",
54 _ => "resource",
55 };
56 format!(
57 "arn:onprem:iam::{}:{}{}{}",
58 account_id, resource_name, path, name
59 )
60 }
61
62 fn generate_resource_id(&self, resource_type: ResourceType) -> String {
63 let prefix = match resource_type {
64 ResourceType::User => "ONPU",
65 ResourceType::Group => "ONPG",
66 ResourceType::Role => "ONPR",
67 ResourceType::Policy => "ONPP",
68 _ => "ONPR",
69 };
70 let uuid_part = uuid::Uuid::new_v4()
71 .to_string()
72 .replace('-', "")
73 .chars()
74 .take(17)
75 .collect::<String>()
76 .to_uppercase();
77 format!("{}{}", prefix, uuid_part)
78 }
79
80 fn resource_limits(&self) -> &ResourceLimits {
81 &self.limits
82 }
83
84 fn validate_service_name(&self, _service: &str) -> Result<()> {
85 Ok(())
87 }
88
89 fn validate_path(&self, path: &str) -> Result<()> {
90 if !path.starts_with('/') || !path.ends_with('/') {
92 return Err(wami::error::AmiError::InvalidParameter {
93 message: format!(
94 "Invalid path: '{}'. Paths must start and end with '/'",
95 path
96 ),
97 });
98 }
99 Ok(())
100 }
101
102 fn generate_service_linked_role_name(
103 &self,
104 service_name: &str,
105 custom_suffix: Option<&str>,
106 ) -> String {
107 if let Some(suffix) = custom_suffix {
108 format!("OnPremServiceRoleFor{}_{}", service_name, suffix)
109 } else {
110 format!("OnPremServiceRoleFor{}", service_name)
111 }
112 }
113
114 fn generate_service_linked_role_path(&self, service_name: &str) -> String {
115 format!("/onprem-service-role/{}/", service_name)
116 }
117}
118
119#[tokio::main]
120async fn main() -> std::result::Result<(), Box<dyn std::error::Error>> {
121 println!("=== Hybrid Cloud Setup ===\n");
122
123 let store = Arc::new(RwLock::new(InMemoryWamiStore::default()));
124
125 println!("Step 1: Note about providers...\n");
127
128 let _onprem_provider = Arc::new(OnPremiseProvider::new("dc1-prod".to_string()));
129 let _aws_provider = Arc::new(AwsProvider::new());
130
131 println!("✓ Providers can be used for ARN transformation:");
132 println!(" - On-Premise (datacenter: dc1-prod)");
133 println!(" - AWS (public cloud)");
134 println!(" - Services now use WamiContext instead of providers");
135
136 let onprem_context = wami::context::WamiContext::builder()
138 .instance_id("dc1-prod")
139 .tenant_path(wami::arn::TenantPath::single(60000001)) .caller_arn(
141 wami::arn::WamiArn::builder()
142 .service(wami::arn::Service::Iam)
143 .tenant_path(wami::arn::TenantPath::single(60000001))
144 .wami_instance("dc1-prod")
145 .resource("user", "admin")
146 .build()?,
147 )
148 .is_root(false)
149 .build()?;
150
151 let aws_context = wami::context::WamiContext::builder()
153 .instance_id("123456789012")
154 .tenant_path(wami::arn::TenantPath::single(70000001)) .caller_arn(
156 wami::arn::WamiArn::builder()
157 .service(wami::arn::Service::Iam)
158 .tenant_path(wami::arn::TenantPath::single(70000001))
159 .wami_instance("123456789012")
160 .resource("user", "admin")
161 .build()?,
162 )
163 .is_root(false)
164 .build()?;
165
166 println!("\n\nStep 2: Creating user in on-premise environment...\n");
168
169 let user_service = UserService::new(store.clone());
170
171 let onprem_req = CreateUserRequest {
172 user_name: "alice-onprem".to_string(),
173 path: Some("/employees/".to_string()),
174 permissions_boundary: None,
175 tags: Some(vec![
176 wami::types::Tag {
177 key: "Environment".to_string(),
178 value: "OnPremise".to_string(),
179 },
180 wami::types::Tag {
181 key: "Datacenter".to_string(),
182 value: "dc1-prod".to_string(),
183 },
184 ]),
185 };
186
187 let alice_onprem = user_service
188 .create_user(&onprem_context, onprem_req)
189 .await?;
190 println!("✓ Created alice-onprem in on-premise:");
191 println!(" - ARN: {}", alice_onprem.arn);
192 println!(" - WAMI ARN: {}", alice_onprem.wami_arn);
193 println!(" - Resource ID: {}", alice_onprem.user_id);
194
195 println!("\n\nStep 3: Creating user in AWS cloud...\n");
197
198 let aws_req = CreateUserRequest {
199 user_name: "alice-cloud".to_string(),
200 path: Some("/employees/".to_string()),
201 permissions_boundary: None,
202 tags: Some(vec![
203 wami::types::Tag {
204 key: "Environment".to_string(),
205 value: "AWS".to_string(),
206 },
207 wami::types::Tag {
208 key: "Region".to_string(),
209 value: "us-east-1".to_string(),
210 },
211 ]),
212 };
213
214 let alice_aws = user_service.create_user(&aws_context, aws_req).await?;
215 println!("✓ Created alice-cloud in AWS:");
216 println!(" - ARN: {}", alice_aws.arn);
217 println!(" - WAMI ARN: {}", alice_aws.wami_arn);
218 println!(" - Resource ID: {}", alice_aws.user_id);
219
220 println!("\n\nStep 4: Understanding hybrid identity federation...\n");
222
223 println!("Both identities represent the same person (alice@company.com):");
224 println!();
225 println!("On-Premise Identity:");
226 println!(" - ARN: {}", alice_onprem.arn);
227 println!(" - For: Legacy applications, internal systems");
228 println!();
229 println!("Cloud Identity:");
230 println!(" - ARN: {}", alice_aws.arn);
231 println!(" - For: Cloud-native applications, external APIs");
232
233 println!("\n\nStep 4: Unified view across hybrid environment...\n");
235
236 let (all_users, _, _) = user_service
237 .list_users(
238 &onprem_context,
239 ListUsersRequest {
240 path_prefix: None,
241 pagination: None,
242 },
243 )
244 .await?;
245 println!(
246 "✓ Total users across hybrid environment: {}",
247 all_users.len()
248 );
249 for user in &all_users {
250 let env = if user.wami_arn.to_string().contains("onprem") {
251 "On-Premise"
252 } else {
253 "Cloud"
254 };
255 println!(" - {} ({}) → {}", user.user_name, env, user.wami_arn);
256 }
257
258 println!("\n\nStep 5: Hybrid cloud use cases...\n");
260
261 println!("WAMI context-based architecture enables:");
262 println!("- On-premise to cloud migration paths");
263 println!("- Unified identity management with WamiContext");
264 println!("- Hybrid application architectures");
265 println!("- Edge computing with centralized IAM");
266 println!("- Consistent resource identification with WAMI ARNs");
267
268 println!("\n✅ Example completed successfully!");
269 println!("Key takeaways:");
270 println!("- WamiContext replaces provider-specific service configuration");
271 println!("- Use different contexts for different environments");
272 println!("- WAMI ARNs provide unified identity layer");
273 println!("- Same store works across all contexts");
274 println!("- Providers can still be used for ARN transformation when needed");
275
276 Ok(())
277}