1use std::collections::BTreeMap;
14use std::sync::Arc;
15
16use parking_lot::RwLock;
17use serde::{Deserialize, Serialize};
18use serde_json::Value;
19
20use fakecloud_core::multi_account::{AccountState, MultiAccountState};
21
22pub const SSOADMIN_SNAPSHOT_SCHEMA_VERSION: u32 = 1;
23
24#[derive(Debug, Clone, Serialize, Deserialize)]
26pub struct StoredRegion {
27 pub region_name: String,
28 pub status: String,
29 pub added_date: i64,
30 pub is_primary: bool,
31}
32
33#[derive(Debug, Clone, Serialize, Deserialize)]
35pub struct StoredInstance {
36 pub arn: String,
37 pub ssoins: String,
39 pub identity_store_id: String,
40 pub owner_account_id: String,
41 #[serde(default)]
42 pub name: Option<String>,
43 pub status: String,
44 pub created_date: i64,
45 #[serde(default)]
46 pub regions: Vec<StoredRegion>,
47 #[serde(default)]
48 pub primary_region: Option<String>,
49 #[serde(default)]
52 pub attr_config: Option<Value>,
53 #[serde(default)]
54 pub attr_config_status: Option<String>,
55}
56
57#[derive(Debug, Clone, Serialize, Deserialize)]
59pub struct StoredManagedPolicy {
60 pub name: String,
61 pub arn: String,
62}
63
64#[derive(Debug, Clone, Serialize, Deserialize)]
66pub struct StoredPermissionSet {
67 pub arn: String,
68 pub instance_arn: String,
69 pub name: String,
70 #[serde(default)]
71 pub description: Option<String>,
72 #[serde(default)]
73 pub session_duration: Option<String>,
74 #[serde(default)]
75 pub relay_state: Option<String>,
76 pub created_date: i64,
77 #[serde(default)]
78 pub inline_policy: Option<String>,
79 #[serde(default)]
81 pub permissions_boundary: Option<Value>,
82 #[serde(default)]
83 pub managed_policies: Vec<StoredManagedPolicy>,
84 #[serde(default)]
86 pub customer_managed: Vec<Value>,
87}
88
89#[derive(Debug, Clone, Serialize, Deserialize)]
91pub struct StoredAssignment {
92 pub account_id: String,
93 pub permission_set_arn: String,
94 pub principal_type: String,
95 pub principal_id: String,
96}
97
98#[derive(Debug, Clone, Serialize, Deserialize)]
100pub struct StoredOpStatus {
101 pub request_id: String,
102 pub status: String,
103 pub target_id: String,
104 pub target_type: String,
105 pub permission_set_arn: String,
106 pub principal_type: String,
107 pub principal_id: String,
108 pub created_date: i64,
109}
110
111#[derive(Debug, Clone, Serialize, Deserialize)]
113pub struct StoredProvisioningStatus {
114 pub request_id: String,
115 pub status: String,
116 #[serde(default)]
117 pub account_id: Option<String>,
118 pub permission_set_arn: String,
119 pub created_date: i64,
120}
121
122#[derive(Debug, Clone, Serialize, Deserialize)]
124pub struct StoredApplication {
125 pub arn: String,
126 pub provider_arn: String,
127 #[serde(default)]
128 pub name: Option<String>,
129 pub account: String,
130 pub instance_arn: String,
131 pub identity_store_arn: String,
132 #[serde(default)]
133 pub status: Option<String>,
134 #[serde(default)]
136 pub portal_options: Option<Value>,
137 #[serde(default)]
138 pub description: Option<String>,
139 pub created_date: i64,
140 #[serde(default)]
141 pub created_from: Option<String>,
142 #[serde(default)]
144 pub assignments: Vec<(String, String)>,
145 #[serde(default)]
146 pub assignment_required: Option<bool>,
147 #[serde(default)]
149 pub access_scopes: BTreeMap<String, Value>,
150 #[serde(default)]
152 pub auth_methods: BTreeMap<String, Value>,
153 #[serde(default)]
155 pub grants: BTreeMap<String, Value>,
156 #[serde(default)]
157 pub session_status: Option<String>,
158}
159
160#[derive(Debug, Clone, Serialize, Deserialize)]
162pub struct StoredTrustedTokenIssuer {
163 pub arn: String,
164 pub instance_arn: String,
165 #[serde(default)]
166 pub name: Option<String>,
167 pub issuer_type: String,
168 #[serde(default)]
170 pub config: Option<Value>,
171}
172
173#[derive(Debug, Clone, Default, Serialize, Deserialize)]
175pub struct SsoAdminData {
176 #[serde(default)]
178 pub instances: BTreeMap<String, StoredInstance>,
179 #[serde(default)]
181 pub permission_sets: BTreeMap<String, StoredPermissionSet>,
182 #[serde(default)]
183 pub assignments: Vec<StoredAssignment>,
184 #[serde(default)]
186 pub aa_create_status: BTreeMap<String, StoredOpStatus>,
187 #[serde(default)]
189 pub aa_delete_status: BTreeMap<String, StoredOpStatus>,
190 #[serde(default)]
192 pub ps_provisioning: BTreeMap<String, StoredProvisioningStatus>,
193 #[serde(default)]
195 pub applications: BTreeMap<String, StoredApplication>,
196 #[serde(default)]
198 pub trusted_token_issuers: BTreeMap<String, StoredTrustedTokenIssuer>,
199 #[serde(default)]
201 pub tags: BTreeMap<String, BTreeMap<String, String>>,
202}
203
204impl AccountState for SsoAdminData {
205 fn new_for_account(_account_id: &str, _region: &str, _endpoint: &str) -> Self {
206 Self::default()
207 }
208}
209
210pub type SharedSsoAdminState = Arc<RwLock<MultiAccountState<SsoAdminData>>>;
211
212#[derive(Debug, Serialize, Deserialize)]
213pub struct SsoAdminSnapshot {
214 pub schema_version: u32,
215 pub accounts: MultiAccountState<SsoAdminData>,
216}
217
218pub fn ensure_default_instance(state: &SharedSsoAdminState, account_id: &str, region: &str) {
227 let mut guard = state.write();
228 let acct = guard.get_or_create(account_id);
229 if !acct.instances.is_empty() {
230 return;
231 }
232 let pad = format!("{account_id:0<16}");
233 let ssoins = format!("ssoins-{}", &pad[..16]);
234 let arn = format!("arn:aws:sso:::instance/{ssoins}");
235 let identity_store_id = format!("d-{}", &pad[..10]);
236 let ts = chrono::Utc::now().timestamp();
237 acct.instances.insert(
238 arn.clone(),
239 StoredInstance {
240 arn,
241 ssoins,
242 identity_store_id,
243 owner_account_id: account_id.to_string(),
244 name: None,
245 status: "ACTIVE".into(),
246 created_date: ts,
247 regions: vec![StoredRegion {
248 region_name: region.to_string(),
249 status: "ACTIVE".into(),
250 added_date: ts,
251 is_primary: true,
252 }],
253 primary_region: Some(region.to_string()),
254 attr_config: None,
255 attr_config_status: None,
256 },
257 );
258}