#![deny(clippy::wildcard_enum_match_arm)]
use nodedb_types::id::DatabaseId;
use crate::types::TenantId;
use super::database_set::DatabaseSet;
use super::role::Role;
#[derive(Debug, Clone)]
pub struct AuthenticatedIdentity {
pub user_id: u64,
pub username: String,
pub tenant_id: TenantId,
pub auth_method: AuthMethod,
pub roles: Vec<Role>,
pub is_superuser: bool,
pub default_database: Option<DatabaseId>,
pub accessible_databases: DatabaseSet,
}
impl AuthenticatedIdentity {
pub fn has_role(&self, role: &Role) -> bool {
self.is_superuser || self.roles.contains(role)
}
pub fn has_any_role(&self, roles: &[Role]) -> bool {
self.is_superuser || roles.iter().any(|r| self.roles.contains(r))
}
pub fn has_cluster_admin(&self) -> bool {
self.is_superuser || self.roles.iter().any(|r| matches!(r, Role::ClusterAdmin))
}
pub fn is_database_owner(&self, db: DatabaseId) -> bool {
self.is_superuser
|| self
.roles
.iter()
.any(|r| matches!(r, Role::DatabaseOwner(d) if *d == db))
}
pub fn can_access_database(&self, db: DatabaseId) -> bool {
self.is_superuser || self.accessible_databases.contains(db)
}
pub fn default_database_set(is_superuser: bool) -> DatabaseSet {
if is_superuser {
DatabaseSet::All
} else {
DatabaseSet::Some(smallvec::smallvec![DatabaseId::DEFAULT])
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum AuthMethod {
ScramSha256,
CleartextPassword,
ApiKey,
Certificate,
Trust,
OidcBearer,
}
#[cfg(test)]
mod tests {
use super::*;
fn test_identity(roles: Vec<Role>, superuser: bool) -> AuthenticatedIdentity {
AuthenticatedIdentity {
user_id: 1,
username: "test".into(),
tenant_id: TenantId::new(1),
auth_method: AuthMethod::Trust,
roles,
is_superuser: superuser,
default_database: None,
accessible_databases: AuthenticatedIdentity::default_database_set(superuser),
}
}
#[test]
fn superuser_has_all_roles() {
let id = test_identity(vec![], true);
assert!(id.has_role(&Role::ReadOnly));
assert!(id.has_role(&Role::TenantAdmin));
assert!(id.has_role(&Role::Custom("anything".into())));
}
#[test]
fn readonly_only_has_readonly() {
let id = test_identity(vec![Role::ReadOnly], false);
assert!(id.has_role(&Role::ReadOnly));
assert!(!id.has_role(&Role::ReadWrite));
assert!(!id.has_role(&Role::TenantAdmin));
}
#[test]
fn superuser_can_access_any_database() {
let id = test_identity(vec![], true);
assert!(id.can_access_database(DatabaseId::new(99)));
}
#[test]
fn regular_user_only_default_database() {
let id = test_identity(vec![Role::ReadOnly], false);
assert!(id.can_access_database(DatabaseId::DEFAULT));
assert!(!id.can_access_database(DatabaseId::new(99)));
}
}