cloudillo_profile/
perm.rs1use axum::{
4 extract::{Path, Request, State},
5 middleware::Next,
6 response::Response,
7};
8
9use crate::prelude::*;
10use cloudillo_core::abac::Environment;
11use cloudillo_core::extract::Auth;
12use cloudillo_core::middleware::PermissionCheckOutput;
13use cloudillo_types::types::ProfileAttrs;
14
15pub fn check_perm_profile(
25 action: &'static str,
26) -> impl Fn(State<App>, Auth, Path<String>, Request, Next) -> PermissionCheckOutput + Clone {
27 move |state, auth, path, req, next| {
28 Box::pin(check_profile_permission(state, auth, path, req, next, action))
29 }
30}
31
32async fn check_profile_permission(
33 State(app): State<App>,
34 Auth(auth_ctx): Auth,
35 Path(id_tag): Path<String>,
36 req: Request,
37 next: Next,
38 action: &str,
39) -> Result<Response, Error> {
40 use tracing::warn;
41
42 let attrs = load_profile_attrs(&app, auth_ctx.tn_id, &id_tag, &auth_ctx.id_tag).await?;
44
45 let environment = Environment::new();
47 let checker = app.permission_checker.read().await;
48
49 let full_action = format!("profile:{}", action);
51
52 if !checker.has_permission(&auth_ctx, &full_action, &attrs, &environment) {
53 warn!(
54 subject = %auth_ctx.id_tag,
55 action = action,
56 target_id_tag = %id_tag,
57 owner_id_tag = %attrs.tenant_tag,
58 profile_type = attrs.profile_type,
59 roles = ?attrs.roles,
60 status = attrs.status,
61 "Profile permission denied"
62 );
63 return Err(Error::PermissionDenied);
64 }
65
66 Ok(next.run(req).await)
67}
68
69async fn load_profile_attrs(
71 app: &App,
72 tn_id: TnId,
73 id_tag: &str,
74 subject_id_tag: &str,
75) -> ClResult<ProfileAttrs> {
76 let subject_roles = app
78 .meta_adapter
79 .read_profile_roles(tn_id, subject_id_tag)
80 .await
81 .ok()
82 .flatten()
83 .map(|roles| roles.into_vec())
84 .unwrap_or_default();
85
86 match app.meta_adapter.get_profile_info(tn_id, id_tag).await {
88 Ok(profile_data) => {
89 let following = false;
92 let connected = false;
93
94 Ok(ProfileAttrs {
95 id_tag: profile_data.id_tag,
96 profile_type: profile_data.r#type,
97 tenant_tag: id_tag.into(), roles: subject_roles,
99 status: "active".into(), following,
101 connected,
102 visibility: "public".into(), })
104 }
105 Err(Error::NotFound) => {
106 Ok(ProfileAttrs {
109 id_tag: id_tag.into(),
110 profile_type: "person".into(),
111 tenant_tag: id_tag.into(),
112 roles: subject_roles,
113 status: "unknown".into(),
114 following: false,
115 connected: false,
116 visibility: "public".into(), })
118 }
119 Err(e) => Err(e),
120 }
121}
122
123