uqa_sql/catalog/security/database/
binding.rs1use super::super::role_bindings;
10use super::{DatabaseAclEntry, DatabasePrivileges, DatabaseSecurity};
11use crate::catalog::roles::{RoleDefinition, RoleIdentity};
12use serde::{Deserialize, Serialize};
13use std::collections::BTreeMap;
14use uqa_core::catalog_acl::AclGrantee;
15
16pub type BoundDatabaseAclEntry = uqa_core::catalog_role::BoundAclEntry<DatabasePrivileges>;
17
18#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
19pub struct BoundDatabaseSecurity {
20 pub role_owner: RoleIdentity,
21 pub acl: Option<Vec<BoundDatabaseAclEntry>>,
22}
23
24fn role_name(
25 roles: &BTreeMap<String, RoleDefinition>,
26 identity: RoleIdentity,
27) -> Result<&str, String> {
28 role_bindings::role_name(roles, identity, "database")
29}
30
31impl BoundDatabaseSecurity {
32 pub fn bootstrap() -> Self {
33 Self {
34 role_owner: RoleDefinition::bootstrap().identity(),
35 acl: None,
36 }
37 }
38
39 pub fn depends_on(&self, role: RoleIdentity) -> bool {
40 self.role_owner == role
41 || self.acl.as_ref().is_some_and(|entries| {
42 entries
43 .iter()
44 .any(|entry| entry.role == Some(role) || entry.grantor == role)
45 })
46 }
47
48 pub fn validate(&self, roles: &BTreeMap<String, RoleDefinition>) -> Result<(), String> {
49 role_name(roles, self.role_owner)?;
50 for entry in self.acl.iter().flatten() {
51 if let Some(grantee) = entry.role {
52 role_name(roles, grantee)?;
53 }
54 role_name(roles, entry.grantor)?;
55 }
56 Ok(())
57 }
58
59 pub fn bind(
60 security: &DatabaseSecurity,
61 roles: &BTreeMap<String, RoleDefinition>,
62 ) -> Result<Self, String> {
63 super::validate_stored_database_security(security, roles)?;
64 let bind = |name: &str| role_bindings::bind_role(roles, name, "database");
65 Ok(Self {
66 role_owner: bind(&security.role_owner)?,
67 acl: security
68 .acl
69 .as_ref()
70 .map(|entries| {
71 entries
72 .iter()
73 .map(|entry| {
74 Ok(BoundDatabaseAclEntry {
75 role: entry.role.role_name().map(bind).transpose()?,
76 grantor: bind(
77 entry.grantor.as_deref().unwrap_or(&security.role_owner),
78 )?,
79 privileges: entry.privileges,
80 grant_options: entry.grant_options,
81 })
82 })
83 .collect::<Result<Vec<_>, String>>()
84 })
85 .transpose()?,
86 })
87 }
88
89 pub fn resolve(
91 &self,
92 roles: &BTreeMap<String, RoleDefinition>,
93 ) -> Result<DatabaseSecurity, String> {
94 let name = |identity| role_name(roles, identity).map(str::to_owned);
95 Ok(DatabaseSecurity {
96 role_owner: name(self.role_owner)?,
97 acl: self
98 .acl
99 .as_ref()
100 .map(|entries| {
101 entries
102 .iter()
103 .map(|entry| {
104 Ok(DatabaseAclEntry {
105 role: entry
106 .role
107 .map(&name)
108 .transpose()?
109 .map_or(AclGrantee::Public, AclGrantee::Role),
110 grantor: Some(name(entry.grantor)?),
111 privileges: entry.privileges,
112 grant_options: entry.grant_options,
113 })
114 })
115 .collect::<Result<Vec<_>, String>>()
116 })
117 .transpose()?,
118 })
119 }
120}
121
122#[cfg(test)]
123mod tests;