1use crate::ast::{CreateRoleStmt, RoleAttribute};
10use serde::{Deserialize, Serialize};
11use std::collections::BTreeSet;
12
13pub mod identity;
14pub mod rename;
15pub mod session;
16pub mod tuple;
17use identity::RoleBinding;
18pub use identity::{RoleIdentity, RoleReference};
19pub mod memberships;
20pub use memberships::{role_can_set, role_inherits};
21
22#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
23pub struct RoleDefinition {
24 pub oid: i64,
25 #[serde(default)]
27 pub object_id: [u8; 16],
28 #[serde(default)]
30 pub revision: u64,
31 pub name: String,
32 pub attributes: BTreeSet<RoleAttribute>,
33 pub connection_limit: i32,
34}
35
36#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
37pub struct RoleMembershipKey {
38 pub role: RoleIdentity,
39 pub member: RoleIdentity,
40 pub grantor: RoleIdentity,
41}
42
43#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
44pub struct RoleMembership {
45 pub oid: i64,
46 pub role: RoleBinding,
47 pub member: RoleBinding,
48 pub grantor: RoleBinding,
49 pub admin_option: bool,
50 pub inherit_option: bool,
51 pub set_option: bool,
52}
53
54impl RoleMembership {
55 pub fn key(&self) -> RoleMembershipKey {
56 RoleMembershipKey {
57 role: self.role.identity(),
58 member: self.member.identity(),
59 grantor: self.grantor.identity(),
60 }
61 }
62}
63
64impl RoleDefinition {
65 pub fn identity(&self) -> RoleIdentity {
66 RoleIdentity {
67 oid: self.oid,
68 object_id: self.object_id,
69 }
70 }
71
72 pub fn bootstrap() -> Self {
73 Self {
74 oid: 10,
75 object_id: RoleIdentity::BOOTSTRAP.object_id,
76 revision: 1,
77 name: "uqa".into(),
78 attributes: BTreeSet::from([
79 RoleAttribute::Superuser,
80 RoleAttribute::Inherit,
81 RoleAttribute::CreateRole,
82 RoleAttribute::CreateDb,
83 RoleAttribute::Login,
84 RoleAttribute::BypassRls,
85 ]),
86 connection_limit: -1,
87 }
88 }
89
90 pub fn from_create(statement: &CreateRoleStmt, oid: i64, object_id: [u8; 16]) -> Self {
91 Self {
92 oid,
93 object_id,
94 revision: 1,
95 name: statement.name.clone(),
96 attributes: statement.attributes.clone(),
97 connection_limit: statement.connection_limit,
98 }
99 }
100
101 pub fn has(&self, attribute: RoleAttribute) -> bool {
102 self.attributes.contains(&attribute)
103 }
104
105 pub fn advance_revision(&mut self) -> Result<(), crate::SQLError> {
106 self.revision = self
107 .revision
108 .checked_add(1)
109 .filter(|_| self.revision != 0)
110 .ok_or_else(|| {
111 crate::SQLError::Internal("invalid or exhausted role tuple revision".into())
112 })?;
113 Ok(())
114 }
115}
116
117pub trait RoleReferenceNames {
119 fn current_role(&self) -> RoleReference;
120 fn session_role(&self) -> RoleReference;
121 fn outer_role(&self) -> RoleReference;
123 fn authenticated_role(&self) -> RoleReference {
124 self.session_role()
125 }
126}
127pub fn resolve_role_specification(
128 names: &dyn RoleReferenceNames,
129 specification: &crate::ast::RoleSpecification,
130) -> RoleReference {
131 match specification {
132 crate::ast::RoleSpecification::Named(name) => name.clone().into(),
133 crate::ast::RoleSpecification::CurrentUser => names.current_role(),
134 crate::ast::RoleSpecification::SessionUser => names.session_role(),
135 }
136}
137
138pub fn resolve_acl_role_specification(
139 names: &dyn RoleReferenceNames,
140 specification: &crate::ast::AclRoleSpecification,
141 roles: &std::collections::BTreeMap<String, RoleDefinition>,
142) -> Result<uqa_core::catalog_acl::AclGrantee, crate::SQLError> {
143 use crate::ast::AclRoleSpecification;
144 use uqa_core::catalog_acl::AclGrantee;
145 match specification {
146 AclRoleSpecification::Public => Ok(AclGrantee::Public),
147 AclRoleSpecification::Role(role) => resolve_role_specification(names, role)
148 .catalog_name(roles)
149 .map(AclGrantee::Role),
150 }
151}
152
153pub fn require_role_exists(
154 roles: &std::collections::BTreeMap<String, RoleDefinition>,
155 name: &str,
156) -> Result<(), crate::SQLError> {
157 if roles.contains_key(name) {
158 return Ok(());
159 }
160 Err(crate::SQLError::Routine {
161 sqlstate: "42704".into(),
162 message: format!("role \"{name}\" does not exist"),
163 })
164}
165pub fn require_set_role(
166 roles: &std::collections::BTreeMap<String, RoleDefinition>,
167 memberships: &std::collections::BTreeMap<RoleMembershipKey, RoleMembership>,
168 current: &(impl identity::RoleSubject + ?Sized),
169 target: &str,
170) -> Result<(), crate::SQLError> {
171 if role_can_set(roles, memberships, current, target) {
172 return Ok(());
173 }
174 Err(crate::SQLError::Routine {
175 sqlstate: "42501".into(),
176 message: format!("must be able to SET ROLE \"{target}\""),
177 })
178}
179
180pub mod definition;
181pub mod dependencies;
182pub mod guards;
183pub mod inquiry;
184pub mod restoration;