uqa_sql/catalog/security/
sequence_inquiry.rs1use super::{
10 sequence::{self as acl, role_has_privilege, AclPrivilege, PrivilegeCheck},
11 BoundSequenceSecurity,
12};
13use crate::catalog::roles::identity::RoleSubject;
14use crate::{
15 catalog::{
16 resolution::RelationResolution,
17 roles::{guards::RoleCatalogGuards, RoleReferenceNames},
18 },
19 SQLError,
20};
21use std::{collections::BTreeMap, ops::Deref};
22use uqa_core::{RelationIdentity, Value};
23
24pub type SequenceSecurityRead<'a> =
25 Box<dyn Deref<Target = BTreeMap<RelationIdentity, BoundSequenceSecurity>> + 'a>;
26pub trait SequenceSecurityCatalog {
27 fn security_read(&self) -> SequenceSecurityRead<'_>;
28}
29pub trait SequencePrivilegeResolution {
30 fn visible_relation_kind(&self, reference: &str) -> Result<RelationResolution, SQLError>;
31 fn sequence_privilege_oid(
32 &self,
33 oid: i64,
34 ) -> Result<Option<(String, RelationIdentity)>, SQLError>;
35}
36pub trait SequenceTablePrivilegeInquiry {
37 fn sequence_table_privileges(
38 &self,
39 relation: &RelationIdentity,
40 subject: &dyn RoleSubject,
41 checks: &[super::table::TablePrivilegeCheck],
42 ) -> Result<bool, SQLError>;
43}
44
45pub struct SequencePrivilegeInquiry<'a> {
46 pub names: &'a dyn RoleReferenceNames,
47 pub roles: &'a dyn RoleCatalogGuards,
48 pub security: &'a dyn SequenceSecurityCatalog,
49 pub resolution: &'a dyn SequencePrivilegeResolution,
50}
51
52impl SequencePrivilegeInquiry<'_> {
53 pub fn ensure_sequence_nextval_privilege(
54 &self,
55 name: &str,
56 relation: &RelationIdentity,
57 ) -> Result<(), SQLError> {
58 self.ensure_sequence_value_privilege(
59 name,
60 relation,
61 &[AclPrivilege::Usage, AclPrivilege::Update],
62 )
63 }
64
65 pub fn ensure_sequence_currval_privilege(
66 &self,
67 name: &str,
68 relation: &RelationIdentity,
69 ) -> Result<(), SQLError> {
70 self.ensure_sequence_value_privilege(
71 name,
72 relation,
73 &[AclPrivilege::Usage, AclPrivilege::Select],
74 )
75 }
76
77 pub fn ensure_sequence_setval_privilege(
78 &self,
79 name: &str,
80 relation: &RelationIdentity,
81 ) -> Result<(), SQLError> {
82 self.ensure_sequence_value_privilege(name, relation, &[AclPrivilege::Update])
83 }
84
85 fn ensure_sequence_value_privilege(
86 &self,
87 name: &str,
88 relation: &RelationIdentity,
89 privileges: &[AclPrivilege],
90 ) -> Result<(), SQLError> {
91 let security = self
92 .security
93 .security_read()
94 .get(relation)
95 .cloned()
96 .ok_or_else(|| {
97 SQLError::Internal(format!("sequence `{name}` has no security metadata"))
98 })?;
99 let current_user = self.names.current_role();
100 let roles = self.roles.role_definitions();
101 let security = security.resolve(&roles).map_err(SQLError::Internal)?;
102 let memberships = self.roles.role_memberships();
103 if privileges.iter().any(|privilege| {
104 role_has_privilege(
105 &security,
106 ¤t_user,
107 PrivilegeCheck {
108 privilege: *privilege,
109 grant_option: false,
110 },
111 &roles,
112 &memberships,
113 )
114 }) {
115 return Ok(());
116 }
117 Err(SQLError::Routine {
118 sqlstate: "42501".into(),
119 message: format!("permission denied for sequence {}", relation.name),
120 })
121 }
122
123 pub fn has_sequence_privilege_value(&self, arguments: &[Value]) -> Result<Value, SQLError> {
124 let Some(arguments) = SequencePrivilegeArguments::parse(arguments)? else {
125 return Ok(Value::Null);
126 };
127 let request = arguments.bind(self.names, self.roles)?;
128 let Some((_, relation)) = request.target.resolve(self.resolution)? else {
129 return Ok(Value::Null);
130 };
131 request.evaluate(&relation, self.roles, self.security)
132 }
133
134 pub fn role_has_sequence_table_privilege(
135 &self,
136 relation: &RelationIdentity,
137 subject: &(impl RoleSubject + ?Sized),
138 privilege: super::table::TableAclPrivilege,
139 grant_option: bool,
140 ) -> Result<bool, SQLError> {
141 self.role_has_sequence_table_privileges(
142 relation,
143 subject,
144 &[super::table::TablePrivilegeCheck {
145 privilege,
146 grant_option,
147 }],
148 )
149 }
150
151 pub fn role_has_sequence_table_privileges(
152 &self,
153 relation: &RelationIdentity,
154 subject: &(impl RoleSubject + ?Sized),
155 checks: &[super::table::TablePrivilegeCheck],
156 ) -> Result<bool, SQLError> {
157 let mut checks = checks
158 .iter()
159 .filter_map(|check| {
160 let privilege = match check.privilege {
161 super::table::TableAclPrivilege::Select => AclPrivilege::Select,
162 super::table::TableAclPrivilege::Update => AclPrivilege::Update,
163 super::table::TableAclPrivilege::Insert
164 | super::table::TableAclPrivilege::Delete
165 | super::table::TableAclPrivilege::Truncate
166 | super::table::TableAclPrivilege::References
167 | super::table::TableAclPrivilege::Trigger
168 | super::table::TableAclPrivilege::Maintain => return None,
169 };
170 Some(PrivilegeCheck {
171 privilege,
172 grant_option: check.grant_option,
173 })
174 })
175 .peekable();
176 if checks.peek().is_none() {
177 return Ok(false);
178 }
179 let security = self
180 .security
181 .security_read()
182 .get(relation)
183 .cloned()
184 .ok_or_else(|| {
185 SQLError::Internal(format!(
186 "sequence `{}` has no security metadata",
187 relation.qualified_name()
188 ))
189 })?;
190 let roles = self.roles.role_definitions();
191 let security = security.resolve(&roles).map_err(SQLError::Internal)?;
192 let memberships = self.roles.role_memberships();
193 Ok(checks.any(|check| role_has_privilege(&security, subject, check, &roles, &memberships)))
194 }
195
196 pub fn ensure_sequence_owner(
197 &self,
198 name: &str,
199 relation: &RelationIdentity,
200 ) -> Result<String, SQLError> {
201 let security = self
202 .security
203 .security_read()
204 .get(relation)
205 .cloned()
206 .ok_or_else(|| {
207 SQLError::Internal(format!("sequence `{name}` has no security metadata"))
208 })?;
209 let roles = self.roles.role_definitions();
210 let owner = security.owner_reference(&roles)?;
211 crate::schema::sequences::ownership::require_sequence_ownership(&relation.name, {
212 let current = self.names.current_role();
213 let memberships = self.roles.role_memberships();
214 crate::catalog::roles::role_inherits(&roles, &memberships, ¤t, &owner)
215 })?;
216 let owner = owner.catalog_name(&roles)?;
217 Ok(owner)
218 }
219}
220
221impl SequenceTablePrivilegeInquiry for SequencePrivilegeInquiry<'_> {
222 fn sequence_table_privileges(
223 &self,
224 relation: &RelationIdentity,
225 subject: &dyn RoleSubject,
226 checks: &[super::table::TablePrivilegeCheck],
227 ) -> Result<bool, SQLError> {
228 self.role_has_sequence_table_privileges(relation, subject, checks)
229 }
230}
231
232mod value;
233pub use value::{
234 missing_sequence, SequencePrivilegeArguments, SequencePrivilegeRequest, SequencePrivilegeTarget,
235};
236
237#[cfg(test)]
238mod tests;