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