alibi_plugins/helpers/
api_key_authorization.rs1use alibi_core::{AuthContext, AuthError, AuthResult};
2
3pub async fn get_owned_api_key(
12 ctx: &AuthContext<impl alibi_core::AuthSchema>,
13 config: &crate::api_key::ApiKeyConfig,
14 key_id: &str,
15 user_id: &str,
16 action: &str,
17) -> AuthResult<alibi_core::ApiKey> {
18 use crate::api_key::{ApiKeyReferences, config_id_matches};
19
20 let api_key = config
21 .read_key(ctx, key_id, false)
22 .await?
23 .ok_or_else(|| AuthError::not_found("API Key not found"))?;
24
25 if !config_id_matches(&api_key.config_id, &config.config_id) {
27 return Err(AuthError::not_found("API Key not found"));
28 }
29
30 match config.references {
31 ApiKeyReferences::User => {
32 if api_key.reference_id != user_id {
33 return Err(AuthError::not_found("API Key not found"));
34 }
35 }
36 ApiKeyReferences::Organization => {
37 require_org_api_key_permission(ctx, user_id, &api_key.reference_id, action).await?;
38 }
39 }
40
41 Ok(api_key)
42}
43
44pub async fn require_org_api_key_permission(
51 ctx: &AuthContext<impl alibi_core::AuthSchema>,
52 user_id: &str,
53 organization_id: &str,
54 action: &str,
55) -> AuthResult<()> {
56 use crate::api_key::{ApiKeyErrorCode, api_key_error};
57 use crate::organization::{
58 DynamicAccessControlConfig, METADATA_CREATOR_ROLE, METADATA_ENABLED, METADATA_ROLES,
59 OrganizationConfig,
60 };
61
62 if !ctx
65 .get_metadata(METADATA_ENABLED)
66 .and_then(serde_json::Value::as_bool)
67 .unwrap_or(false)
68 {
69 return Err(api_key_error(ApiKeyErrorCode::OrganizationPluginRequired));
70 }
71
72 let Some(member) = ctx.database.get_member(organization_id, user_id).await? else {
73 return Err(api_key_error(ApiKeyErrorCode::UserNotMemberOfOrganization));
74 };
75
76 let creator_role = ctx
80 .get_metadata(METADATA_CREATOR_ROLE)
81 .and_then(serde_json::Value::as_str)
82 .map_or_else(|| "owner".to_owned(), str::to_owned);
83 let config = OrganizationConfig {
84 roles: ctx
85 .get_metadata(METADATA_ROLES)
86 .and_then(|value| serde_json::from_value(value.clone()).ok())
87 .flatten(),
88 access_control: ctx
89 .get_metadata("organization.access_control")
90 .and_then(|value| serde_json::from_value(value.clone()).ok())
91 .flatten(),
92 dynamic_access_control: DynamicAccessControlConfig {
93 enabled: ctx
94 .get_metadata("organization.dynamic_roles.enabled")
95 .and_then(serde_json::Value::as_bool)
96 .unwrap_or(false),
97 ..Default::default()
98 },
99 ..Default::default()
100 };
101 if member.role.split(',').any(|role| role == creator_role) {
104 return crate::organization::handlers::extension_common::organization_roles(
105 &config,
106 ctx,
107 organization_id,
108 )
109 .await
110 .map(|_| ())
111 .map_err(|_error| api_key_error(ApiKeyErrorCode::InsufficientApiKeyPermissions));
112 }
113
114 let allowed = crate::organization::handlers::extension_common::has_action(
117 &member.role,
118 "apiKey",
119 action,
120 &config,
121 ctx,
122 organization_id,
123 )
124 .await
125 .unwrap_or(false);
126
127 if allowed {
128 Ok(())
129 } else {
130 Err(api_key_error(
131 ApiKeyErrorCode::InsufficientApiKeyPermissions,
132 ))
133 }
134}