use alibi_core::{AuthContext, AuthError, AuthResult};
pub async fn get_owned_api_key(
ctx: &AuthContext<impl alibi_core::AuthSchema>,
config: &crate::api_key::ApiKeyConfig,
key_id: &str,
user_id: &str,
action: &str,
) -> AuthResult<alibi_core::ApiKey> {
use crate::api_key::{ApiKeyReferences, config_id_matches};
let api_key = config
.read_key(ctx, key_id, false)
.await?
.ok_or_else(|| AuthError::not_found("API Key not found"))?;
if !config_id_matches(&api_key.config_id, &config.config_id) {
return Err(AuthError::not_found("API Key not found"));
}
match config.references {
ApiKeyReferences::User => {
if api_key.reference_id != user_id {
return Err(AuthError::not_found("API Key not found"));
}
}
ApiKeyReferences::Organization => {
require_org_api_key_permission(ctx, user_id, &api_key.reference_id, action).await?;
}
}
Ok(api_key)
}
pub async fn require_org_api_key_permission(
ctx: &AuthContext<impl alibi_core::AuthSchema>,
user_id: &str,
organization_id: &str,
action: &str,
) -> AuthResult<()> {
use crate::api_key::{ApiKeyErrorCode, api_key_error};
use crate::organization::{
DynamicAccessControlConfig, METADATA_CREATOR_ROLE, METADATA_ENABLED, METADATA_ROLES,
OrganizationConfig,
};
if !ctx
.get_metadata(METADATA_ENABLED)
.and_then(serde_json::Value::as_bool)
.unwrap_or(false)
{
return Err(api_key_error(ApiKeyErrorCode::OrganizationPluginRequired));
}
let Some(member) = ctx.database.get_member(organization_id, user_id).await? else {
return Err(api_key_error(ApiKeyErrorCode::UserNotMemberOfOrganization));
};
let creator_role = ctx
.get_metadata(METADATA_CREATOR_ROLE)
.and_then(serde_json::Value::as_str)
.map_or_else(|| "owner".to_owned(), str::to_owned);
let config = OrganizationConfig {
roles: ctx
.get_metadata(METADATA_ROLES)
.and_then(|value| serde_json::from_value(value.clone()).ok())
.flatten(),
access_control: ctx
.get_metadata("organization.access_control")
.and_then(|value| serde_json::from_value(value.clone()).ok())
.flatten(),
dynamic_access_control: DynamicAccessControlConfig {
enabled: ctx
.get_metadata("organization.dynamic_roles.enabled")
.and_then(serde_json::Value::as_bool)
.unwrap_or(false),
..Default::default()
},
..Default::default()
};
if member.role.split(',').any(|role| role == creator_role) {
return crate::organization::handlers::extension_common::organization_roles(
&config,
ctx,
organization_id,
)
.await
.map(|_| ())
.map_err(|_error| api_key_error(ApiKeyErrorCode::InsufficientApiKeyPermissions));
}
let allowed = crate::organization::handlers::extension_common::has_action(
&member.role,
"apiKey",
action,
&config,
ctx,
organization_id,
)
.await
.unwrap_or(false);
if allowed {
Ok(())
} else {
Err(api_key_error(
ApiKeyErrorCode::InsufficientApiKeyPermissions,
))
}
}