bios_iam/console_interface/api/
iam_ci_role_api.rs

1use crate::basic::dto::iam_filer_dto::IamRoleFilterReq;
2use crate::basic::dto::iam_role_dto::{IamRoleRelAccountCertResp, IamRoleSummaryResp};
3use bios_basic::rbum::helper::rbum_scope_helper::check_without_owner_and_unsafe_fill_ctx;
4use bios_basic::rbum::serv::rbum_crud_serv::RbumCrudOperation;
5use bios_basic::rbum::serv::rbum_item_serv::{RbumItemCrudOperation, RbumItemServ};
6use itertools::Itertools;
7use tardis::log::error;
8
9use crate::basic::serv::iam_app_serv::IamAppServ;
10use crate::basic::serv::iam_cert_serv::IamCertServ;
11use crate::basic::serv::iam_role_serv::IamRoleServ;
12use crate::iam_config::IamBasicConfigApi;
13use crate::iam_constants::{self, RBUM_SCOPE_LEVEL_APP};
14use bios_basic::helper::request_helper::try_set_real_ip_from_req_to_ctx;
15use bios_basic::process::task_processor::TaskProcessor;
16use bios_basic::rbum::dto::rbum_filer_dto::{RbumBasicFilterReq, RbumCertFilterReq};
17use tardis::tokio;
18use tardis::web::context_extractor::TardisContextExtractor;
19use tardis::web::poem::Request;
20use tardis::web::poem_openapi;
21use tardis::web::poem_openapi::param::{Path, Query};
22use tardis::web::web_resp::{TardisApiResult, TardisPage, TardisResp, Void};
23
24#[derive(Clone, Default)]
25pub struct IamCiRoleApi;
26
27/// # Interface Console Manage Cert API
28/// 接口控制台管理证书API
29///
30/// Allow Management Of aksk (an authentication method between applications)
31/// 允许管理aksk(应用之间的一种认证方式)
32#[poem_openapi::OpenApi(prefix_path = "/ci/role", tag = "bios_basic::ApiTag::Interface")]
33impl IamCiRoleApi {
34    /// Get role system admin
35    ///
36    /// 获取角色租户管理员
37    #[oai(path = "/system/admin", method = "get")]
38    async fn get_role_tenant_admin(&self, mut ctx: TardisContextExtractor, request: &Request) -> TardisApiResult<String> {
39        let funs = iam_constants::get_tardis_inst();
40        check_without_owner_and_unsafe_fill_ctx(request, &funs, &mut ctx.0)?;
41        try_set_real_ip_from_req_to_ctx(request, &ctx.0).await?;
42        TardisResp::ok(funs.iam_basic_role_sys_admin_id())
43    }
44
45    /// Get role tenant admin
46    ///
47    /// 获取角色租户管理员
48    #[oai(path = "/tenant/admin", method = "get")]
49    async fn get_sub_role_tenant_admin(&self, mut ctx: TardisContextExtractor, request: &Request) -> TardisApiResult<String> {
50        let funs = iam_constants::get_tardis_inst();
51        check_without_owner_and_unsafe_fill_ctx(request, &funs, &mut ctx.0)?;
52        try_set_real_ip_from_req_to_ctx(request, &ctx.0).await?;
53        let tenant_admin_role_id =
54            IamRoleServ::get_embed_sub_role_id(&funs.iam_basic_role_tenant_admin_id(), &funs, &IamCertServ::use_sys_or_tenant_ctx_unsafe(ctx.0.clone())?).await?;
55        TardisResp::ok(tenant_admin_role_id)
56    }
57
58    /// Get role app admin
59    ///
60    /// 获取角色项目管理员
61    #[oai(path = "/app/admin", method = "get")]
62    async fn get_role_app_admin(&self, mut ctx: TardisContextExtractor, request: &Request) -> TardisApiResult<String> {
63        let funs = iam_constants::get_tardis_inst();
64        check_without_owner_and_unsafe_fill_ctx(request, &funs, &mut ctx.0)?;
65        try_set_real_ip_from_req_to_ctx(request, &ctx.0).await?;
66        let app_admin_role_id = IamRoleServ::get_embed_sub_role_id(&funs.iam_basic_role_app_admin_id(), &funs, &ctx.0).await?;
67        TardisResp::ok(app_admin_role_id)
68    }
69
70    /// Get verify role tenant admin
71    /// 验证角色租户管理员
72    #[oai(path = "/verify/tenant/admin", method = "get")]
73    async fn get_verify_role_tenant_admin(&self, mut ctx: TardisContextExtractor, request: &Request) -> TardisApiResult<bool> {
74        let funs = iam_constants::get_tardis_inst();
75        check_without_owner_and_unsafe_fill_ctx(request, &funs, &mut ctx.0)?;
76        try_set_real_ip_from_req_to_ctx(request, &ctx.0).await?;
77        let mut verify_tenant_admin = false;
78        for role in &ctx.0.roles {
79            if role.contains(&funs.iam_basic_role_tenant_admin_id()) {
80                verify_tenant_admin = true;
81            }
82        }
83        TardisResp::ok(verify_tenant_admin)
84    }
85
86    /// Batch add Role Rel Account
87    /// 批量添加角色关联账号
88    #[oai(path = "/:id/account/batch/:account_ids", method = "put")]
89    async fn batch_add_rel_account(&self, id: Path<String>, account_ids: Path<String>, mut ctx: TardisContextExtractor, request: &Request) -> TardisApiResult<Void> {
90        let mut funs = iam_constants::get_tardis_inst();
91        check_without_owner_and_unsafe_fill_ctx(request, &funs, &mut ctx.0)?;
92        try_set_real_ip_from_req_to_ctx(request, &ctx.0).await?;
93        funs.begin().await?;
94        let app_id = IamAppServ::get_id_by_ctx(&ctx.0, &funs)?;
95        let split = account_ids.0.split(',').collect::<Vec<_>>();
96        for s in split {
97            IamAppServ::add_rel_account(&app_id, s, true, &funs, &ctx.0).await?;
98            IamRoleServ::add_rel_account(&id.0, s, Some(RBUM_SCOPE_LEVEL_APP), &funs, &ctx.0).await?;
99        }
100        funs.commit().await?;
101        ctx.0.execute_task().await?;
102        TardisResp::ok(Void {})
103    }
104
105    /// Batch delete Role Rel Account
106    /// 批量删除角色关联账号
107    #[oai(path = "/:id/account/batch/:account_ids", method = "delete")]
108    async fn batch_delete_rel_account(&self, id: Path<String>, account_ids: Path<String>, mut ctx: TardisContextExtractor, request: &Request) -> TardisApiResult<Void> {
109        let mut funs = iam_constants::get_tardis_inst();
110        check_without_owner_and_unsafe_fill_ctx(request, &funs, &mut ctx.0)?;
111        try_set_real_ip_from_req_to_ctx(request, &ctx.0).await?;
112        funs.begin().await?;
113        let split = account_ids.0.split(',').collect::<Vec<_>>();
114        for s in split {
115            IamRoleServ::delete_rel_account(&id.0, s, Some(RBUM_SCOPE_LEVEL_APP), &funs, &ctx.0).await?;
116        }
117        funs.commit().await?;
118        ctx.0.execute_task().await?;
119        TardisResp::ok(Void {})
120    }
121
122    /// Delete Role Rel Account
123    /// 删除角色关联账号
124    #[oai(path = "/:id/account/:account_id", method = "delete")]
125    async fn delete_rel_account(&self, id: Path<String>, account_id: Path<String>, mut ctx: TardisContextExtractor, request: &Request) -> TardisApiResult<Void> {
126        let mut funs = iam_constants::get_tardis_inst();
127        check_without_owner_and_unsafe_fill_ctx(request, &funs, &mut ctx.0)?;
128        try_set_real_ip_from_req_to_ctx(request, &ctx.0).await?;
129        funs.begin().await?;
130        IamRoleServ::delete_rel_account(&id.0, &account_id.0, Some(RBUM_SCOPE_LEVEL_APP), &funs, &ctx.0).await?;
131        funs.commit().await?;
132        ctx.0.execute_task().await?;
133        TardisResp::ok(Void {})
134    }
135
136    /// Add Role Rel Account
137    /// 添加角色关联账号
138    #[oai(path = "/:id/apps/account/batch", method = "put")]
139    async fn batch_add_apps_rel_account(
140        &self,
141        id: Path<String>,
142        app_ids: Query<String>,
143        account_ids: Query<String>,
144        mut ctx: TardisContextExtractor,
145        request: &Request,
146    ) -> TardisApiResult<Option<String>> {
147        let funs = iam_constants::get_tardis_inst();
148        check_without_owner_and_unsafe_fill_ctx(request, &funs, &mut ctx.0)?;
149        try_set_real_ip_from_req_to_ctx(request, &ctx.0).await?;
150        let ctx = ctx.0;
151        let ctx_clone = ctx.clone();
152        ctx.add_async_task(Box::new(|| {
153            Box::pin(async move {
154                let task_handle = tokio::spawn(async move {
155                    let mut funs = iam_constants::get_tardis_inst();
156                    if let Err(err) = funs.begin().await {
157                        error!("[IAM] batch_add_apps_rel_account begin error: {:?}", err);
158                        return;
159                    }
160                    let apps_split: Vec<&str> = app_ids.0.split(',').collect::<Vec<_>>();
161                    let account_split: Vec<&str> = account_ids.0.split(',').collect::<Vec<_>>();
162                    for app_id in apps_split {
163                        let mock_app_ctx = IamCertServ::try_use_app_ctx(ctx_clone.clone(), Some(app_id.to_string())).unwrap_or(ctx_clone.clone());
164                        for account_id in account_split.clone() {
165                            let _ = IamAppServ::add_rel_account(app_id, account_id, true, &funs, &mock_app_ctx).await;
166                            let _ = IamRoleServ::add_rel_account(&id.0, account_id, Some(RBUM_SCOPE_LEVEL_APP), &funs, &mock_app_ctx).await;
167                        }
168                    }
169                    if let Err(err) = funs.commit().await {
170                        error!("[IAM] batch_add_apps_rel_account commit error: {:?}", err);
171                    }
172                });
173                task_handle.await.unwrap();
174                Ok(())
175            })
176        }))
177        .await?;
178        ctx.execute_task().await?;
179        if let Some(task_id) = TaskProcessor::get_task_id_with_ctx(&ctx).await? {
180            TardisResp::accepted(Some(task_id))
181        } else {
182            TardisResp::ok(None)
183        }
184    }
185
186    /// Add Role Rel Account
187    /// 添加角色关联账号
188    #[oai(path = "/:id/apps/account/batch", method = "delete")]
189    async fn batch_delete_apps_rel_account(
190        &self,
191        id: Path<String>,
192        app_ids: Query<String>,
193        account_ids: Query<String>,
194        mut ctx: TardisContextExtractor,
195        request: &Request,
196    ) -> TardisApiResult<Void> {
197        let mut funs = iam_constants::get_tardis_inst();
198        check_without_owner_and_unsafe_fill_ctx(request, &funs, &mut ctx.0)?;
199        try_set_real_ip_from_req_to_ctx(request, &ctx.0).await?;
200        let ctx = ctx.0;
201        funs.begin().await?;
202        let apps_split: Vec<&str> = app_ids.0.split(',').collect::<Vec<_>>();
203        let account_split: Vec<&str> = account_ids.0.split(',').collect::<Vec<_>>();
204        for app_id in apps_split {
205            let mock_app_ctx = IamCertServ::try_use_app_ctx(ctx.clone(), Some(app_id.to_string()))?;
206            for account_id in account_split.clone() {
207                IamRoleServ::delete_rel_account(&id.0, account_id, Some(RBUM_SCOPE_LEVEL_APP), &funs, &mock_app_ctx).await?;
208            }
209        }
210        funs.commit().await?;
211        ctx.execute_task().await?;
212        TardisResp::ok(Void {})
213    }
214
215    /// get Rel Account by role_code
216    /// 根据角色编码获取关联账号
217    #[oai(path = "/:role_code/accounts", method = "get")]
218    async fn get_rel_accounts(&self, role_code: Path<String>, mut ctx: TardisContextExtractor, request: &Request) -> TardisApiResult<Vec<IamRoleRelAccountCertResp>> {
219        let funs = iam_constants::get_tardis_inst();
220        check_without_owner_and_unsafe_fill_ctx(request, &funs, &mut ctx.0)?;
221        try_set_real_ip_from_req_to_ctx(request, &ctx.0).await?;
222        let role_id = RbumItemServ::find_one_rbum(
223            &RbumBasicFilterReq {
224                code: Some(role_code.0),
225                ..Default::default()
226            },
227            &funs,
228            &ctx.0,
229        )
230        .await?
231        .ok_or_else(|| funs.err().internal_error("iam_ci_role", "get_rel_accounts", "role is not found", "404-iam-res-not-exist"))?
232        .id;
233        let account_ids = IamRoleServ::find_id_rel_accounts(&role_id, None, None, &funs, &ctx.0).await?;
234        let certs = IamCertServ::find_certs(
235            &RbumCertFilterReq {
236                basic: RbumBasicFilterReq {
237                    with_sub_own_paths: true,
238                    ..Default::default()
239                },
240                rel_rbum_ids: Some(account_ids.clone()),
241                ..Default::default()
242            },
243            None,
244            None,
245            &funs,
246            &ctx.0,
247        )
248        .await?
249        .into_iter()
250        .map(|r| (r.rel_rbum_id, r.rel_rbum_cert_conf_name.unwrap_or_default(), r.ak))
251        .collect_vec();
252        let result = account_ids
253            .iter()
254            .map(|account_id| IamRoleRelAccountCertResp {
255                account_id: account_id.clone(),
256                certs: certs.iter().filter(|cert| &cert.0 == account_id).map(|r| (r.1.clone(), r.2.clone())).collect(),
257            })
258            .collect_vec();
259        TardisResp::ok(result)
260    }
261
262    /// Find Roles
263    /// 查找角色
264    #[allow(clippy::too_many_arguments)]
265    #[oai(path = "/", method = "get")]
266    async fn paginate(
267        &self,
268        id: Query<Option<String>>,
269        name: Query<Option<String>>,
270        app_id: Query<Option<String>>,
271        in_base: Query<Option<bool>>,
272        in_embed: Query<Option<bool>>,
273        extend_role_id: Query<Option<String>>,
274        with_sub: Query<Option<bool>>,
275        page_number: Query<u32>,
276        page_size: Query<u32>,
277        desc_by_create: Query<Option<bool>>,
278        desc_by_update: Query<Option<bool>>,
279        mut ctx: TardisContextExtractor,
280        request: &Request,
281    ) -> TardisApiResult<TardisPage<IamRoleSummaryResp>> {
282        let funs = iam_constants::get_tardis_inst();
283        check_without_owner_and_unsafe_fill_ctx(request, &funs, &mut ctx.0)?;
284        let ctx = IamCertServ::try_use_app_ctx(ctx.0, app_id.0)?;
285        try_set_real_ip_from_req_to_ctx(request, &ctx).await?;
286        let result = IamRoleServ::paginate_items(
287            &IamRoleFilterReq {
288                basic: RbumBasicFilterReq {
289                    ids: id.0.map(|id| vec![id]),
290                    name: name.0,
291                    with_sub_own_paths: with_sub.0.unwrap_or(false),
292                    ..Default::default()
293                },
294                in_base: in_base.0,
295                in_embed: in_embed.0,
296                extend_role_id: extend_role_id.0,
297                ..Default::default()
298            },
299            page_number.0,
300            page_size.0,
301            desc_by_create.0,
302            desc_by_update.0,
303            &funs,
304            &ctx,
305        )
306        .await?;
307        ctx.execute_task().await?;
308        TardisResp::ok(result)
309    }
310}