use nodedb_types::error::sqlstate;
use nodedb_types::id::DatabaseId;
use crate::control::security::audit::AuditEvent;
use crate::control::security::identity::AuthenticatedIdentity;
use crate::control::state::SharedState;
use super::super::super::result::DdlError;
use super::support::ddl_err;
pub(in crate::control::server::shared::ddl::neutral) fn require_superuser(
state: &SharedState,
identity: &AuthenticatedIdentity,
db_id: Option<DatabaseId>,
action: &str,
) -> Result<(), DdlError> {
if identity.is_superuser {
Ok(())
} else {
audit_permission_denied(state, identity, db_id, action);
Err(ddl_err(
sqlstate::INSUFFICIENT_PRIVILEGE,
format!("permission denied: {action} requires superuser"),
))
}
}
pub(super) fn require_cluster_admin(
state: &SharedState,
identity: &AuthenticatedIdentity,
db_id: Option<DatabaseId>,
action: &str,
) -> Result<(), DdlError> {
if identity.has_cluster_admin() {
Ok(())
} else {
audit_permission_denied(state, identity, db_id, action);
Err(ddl_err(
sqlstate::INSUFFICIENT_PRIVILEGE,
format!("permission denied: {action} requires cluster_admin or superuser"),
))
}
}
pub(super) fn require_database_owner(
state: &SharedState,
identity: &AuthenticatedIdentity,
db_id: DatabaseId,
action: &str,
) -> Result<(), DdlError> {
if identity.is_database_owner(db_id) {
Ok(())
} else {
audit_permission_denied(state, identity, Some(db_id), action);
Err(ddl_err(
sqlstate::INSUFFICIENT_PRIVILEGE,
format!(
"permission denied: {action} requires database_owner of this database or superuser"
),
))
}
}
pub(super) fn require_database_owner_or_higher(
state: &SharedState,
identity: &AuthenticatedIdentity,
db_id: DatabaseId,
action: &str,
) -> Result<(), DdlError> {
if identity.is_superuser || identity.has_cluster_admin() || identity.is_database_owner(db_id) {
Ok(())
} else {
audit_permission_denied(state, identity, Some(db_id), action);
Err(ddl_err(
sqlstate::INSUFFICIENT_PRIVILEGE,
format!(
"permission denied: {action} requires database_owner of this database, \
cluster_admin, or superuser"
),
))
}
}
pub(in crate::control::server::shared::ddl::neutral) fn require_tenant_admin(
identity: &AuthenticatedIdentity,
action: &str,
) -> Result<(), DdlError> {
use crate::control::security::identity::Role;
if identity.is_superuser || identity.has_role(&Role::TenantAdmin) {
Ok(())
} else {
Err(ddl_err(
sqlstate::INSUFFICIENT_PRIVILEGE,
format!("permission denied: only superuser or tenant_admin can {action}"),
))
}
}
fn audit_permission_denied(
state: &SharedState,
identity: &AuthenticatedIdentity,
db_id: Option<DatabaseId>,
action: &str,
) {
state.audit_record_with_db(
AuditEvent::PermissionDenied,
Some(identity.tenant_id),
db_id,
&identity.username,
action,
);
}