1use std::collections::BTreeMap;
13use std::fmt;
14use std::mem::size_of;
15use std::ops::BitOrAssign;
16use std::str::FromStr;
17
18use crate::adt::system::Oid;
19use anyhow::{Error, anyhow};
20use bitflags::bitflags;
21use mz_ore::soft_assert_no_log;
22use mz_ore::str::StrExt;
23use mz_persist_types::columnar::FixedSizeCodec;
24use mz_proto::{RustType, TryFromProtoError};
25#[cfg(any(test, feature = "proptest"))]
26use proptest::arbitrary::Arbitrary;
27#[cfg(any(test, feature = "proptest"))]
28use proptest::prelude::*;
29#[cfg(any(test, feature = "proptest"))]
30use proptest::strategy::{BoxedStrategy, Strategy};
31#[cfg(any(test, feature = "proptest"))]
32use proptest_derive::Arbitrary;
33use serde::{Deserialize, Serialize};
34
35use crate::role_id::RoleId;
36
37include!(concat!(env!("OUT_DIR"), "/mz_repr.adt.mz_acl_item.rs"));
38
39const INSERT_CHAR: char = 'a';
41const SELECT_CHAR: char = 'r';
43const UPDATE_CHAR: char = 'w';
45const DELETE_CHAR: char = 'd';
47const USAGE_CHAR: char = 'U';
49const CREATE_CHAR: char = 'C';
51const CREATE_ROLE_CHAR: char = 'R';
53const CREATE_DB_CHAR: char = 'B';
55const CREATE_CLUSTER_CHAR: char = 'N';
57const CREATE_NETWORK_POLICY_CHAR: char = 'P';
59
60const INSERT_STR: &str = "INSERT";
61const SELECT_STR: &str = "SELECT";
62const UPDATE_STR: &str = "UPDATE";
63const DELETE_STR: &str = "DELETE";
64const USAGE_STR: &str = "USAGE";
65const CREATE_STR: &str = "CREATE";
66const CREATE_ROLE_STR: &str = "CREATEROLE";
67const CREATE_DB_STR: &str = "CREATEDB";
68const CREATE_CLUSTER_STR: &str = "CREATECLUSTER";
69const CREATE_NETWORK_POLICY_STR: &str = "CREATENETWORKPOLICY";
70
71pub const PUBLIC_ROLE_OID: Oid = Oid(0);
74
75#[derive(
89 Clone,
90 Copy,
91 PartialEq,
92 Eq,
93 PartialOrd,
94 Ord,
95 Hash,
96 Serialize,
97 Deserialize
98)]
99#[serde(from = "AclModeSerde", into = "AclModeSerde")]
100pub struct AclMode(u64);
101
102bitflags! {
103 impl AclMode: u64 {
104 const INSERT = 1 << 0;
106 const SELECT = 1 << 1;
107 const UPDATE = 1 << 2;
108 const DELETE = 1 << 3;
109 const USAGE = 1 << 8;
110 const CREATE = 1 << 9;
111
112 const CREATE_CLUSTER = 1 << 29;
114 const CREATE_DB = 1 << 30;
115 const CREATE_ROLE = 1 << 31;
116 const CREATE_NETWORK_POLICY = 1 << 32;
117
118 }
121}
122
123#[derive(Serialize, Deserialize)]
125struct AclModeSerde {
126 bits: u64,
127}
128
129impl From<AclModeSerde> for AclMode {
130 fn from(AclModeSerde { bits }: AclModeSerde) -> Self {
131 AclMode::from_bits_retain(bits)
132 }
133}
134
135impl From<AclMode> for AclModeSerde {
136 fn from(acl_mode: AclMode) -> Self {
137 AclModeSerde {
138 bits: acl_mode.bits(),
139 }
140 }
141}
142
143impl fmt::Debug for AclMode {
145 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
146 if self.is_empty() {
147 f.write_str("(empty)")
148 } else {
149 bitflags::parser::to_writer(self, f)
150 }
151 }
152}
153
154impl AclMode {
155 pub fn parse_single_privilege(s: &str) -> Result<Self, Error> {
156 match s.trim().to_uppercase().as_str() {
157 INSERT_STR => Ok(AclMode::INSERT),
158 SELECT_STR => Ok(AclMode::SELECT),
159 UPDATE_STR => Ok(AclMode::UPDATE),
160 DELETE_STR => Ok(AclMode::DELETE),
161 USAGE_STR => Ok(AclMode::USAGE),
162 CREATE_STR => Ok(AclMode::CREATE),
163 CREATE_ROLE_STR => Ok(AclMode::CREATE_ROLE),
164 CREATE_DB_STR => Ok(AclMode::CREATE_DB),
165 CREATE_CLUSTER_STR => Ok(AclMode::CREATE_CLUSTER),
166 CREATE_NETWORK_POLICY_STR => Ok(AclMode::CREATE_NETWORK_POLICY),
167 _ => Err(anyhow!("{}", s.quoted())),
168 }
169 }
170
171 pub fn parse_multiple_privileges(s: &str) -> Result<Self, Error> {
172 let mut acl_mode = AclMode::empty();
173 for privilege in s.split(',') {
174 let privilege = AclMode::parse_single_privilege(privilege)?;
175 acl_mode.bitor_assign(privilege);
176 }
177 Ok(acl_mode)
178 }
179
180 pub fn to_error_string(&self) -> String {
181 self.explode().join(", ")
182 }
183
184 pub fn explode(&self) -> Vec<&'static str> {
185 let mut privileges = Vec::new();
186 if self.contains(AclMode::SELECT) {
187 privileges.push(SELECT_STR);
188 }
189 if self.contains(AclMode::INSERT) {
190 privileges.push(INSERT_STR);
191 }
192 if self.contains(AclMode::UPDATE) {
193 privileges.push(UPDATE_STR);
194 }
195 if self.contains(AclMode::DELETE) {
196 privileges.push(DELETE_STR);
197 }
198 if self.contains(AclMode::USAGE) {
199 privileges.push(USAGE_STR);
200 }
201 if self.contains(AclMode::CREATE) {
202 privileges.push(CREATE_STR);
203 }
204 if self.contains(AclMode::CREATE_ROLE) {
205 privileges.push(CREATE_ROLE_STR);
206 }
207 if self.contains(AclMode::CREATE_DB) {
208 privileges.push(CREATE_DB_STR);
209 }
210 if self.contains(AclMode::CREATE_CLUSTER) {
211 privileges.push(CREATE_CLUSTER_STR);
212 }
213 if self.contains(AclMode::CREATE_NETWORK_POLICY) {
214 privileges.push(CREATE_NETWORK_POLICY_STR);
215 }
216 privileges
217 }
218}
219
220impl FromStr for AclMode {
221 type Err = Error;
222
223 fn from_str(s: &str) -> Result<Self, Self::Err> {
224 let mut acl_mode = AclMode::empty();
225 for c in s.chars() {
226 match c {
227 INSERT_CHAR => acl_mode.bitor_assign(AclMode::INSERT),
228 SELECT_CHAR => acl_mode.bitor_assign(AclMode::SELECT),
229 UPDATE_CHAR => acl_mode.bitor_assign(AclMode::UPDATE),
230 DELETE_CHAR => acl_mode.bitor_assign(AclMode::DELETE),
231 USAGE_CHAR => acl_mode.bitor_assign(AclMode::USAGE),
232 CREATE_CHAR => acl_mode.bitor_assign(AclMode::CREATE),
233 CREATE_ROLE_CHAR => acl_mode.bitor_assign(AclMode::CREATE_ROLE),
234 CREATE_DB_CHAR => acl_mode.bitor_assign(AclMode::CREATE_DB),
235 CREATE_CLUSTER_CHAR => acl_mode.bitor_assign(AclMode::CREATE_CLUSTER),
236 CREATE_NETWORK_POLICY_CHAR => acl_mode.bitor_assign(AclMode::CREATE_NETWORK_POLICY),
237 _ => return Err(anyhow!("invalid privilege '{c}' in acl mode '{s}'")),
238 }
239 }
240 Ok(acl_mode)
241 }
242}
243
244impl fmt::Display for AclMode {
245 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
246 if self.contains(AclMode::INSERT) {
249 write!(f, "{INSERT_CHAR}")?;
250 }
251 if self.contains(AclMode::SELECT) {
252 write!(f, "{SELECT_CHAR}")?;
253 }
254 if self.contains(AclMode::UPDATE) {
255 write!(f, "{UPDATE_CHAR}")?;
256 }
257 if self.contains(AclMode::DELETE) {
258 write!(f, "{DELETE_CHAR}")?;
259 }
260 if self.contains(AclMode::USAGE) {
261 write!(f, "{USAGE_CHAR}")?;
262 }
263 if self.contains(AclMode::CREATE) {
264 write!(f, "{CREATE_CHAR}")?;
265 }
266 if self.contains(AclMode::CREATE_ROLE) {
267 write!(f, "{CREATE_ROLE_CHAR}")?;
268 }
269 if self.contains(AclMode::CREATE_DB) {
270 write!(f, "{CREATE_DB_CHAR}")?;
271 }
272 if self.contains(AclMode::CREATE_CLUSTER) {
273 write!(f, "{CREATE_CLUSTER_CHAR}")?;
274 }
275 if self.contains(AclMode::CREATE_NETWORK_POLICY) {
276 write!(f, "{CREATE_NETWORK_POLICY_CHAR}")?;
277 }
278 Ok(())
279 }
280}
281
282impl RustType<ProtoAclMode> for AclMode {
283 fn into_proto(&self) -> ProtoAclMode {
284 ProtoAclMode {
285 acl_mode: self.bits(),
286 }
287 }
288
289 fn from_proto(proto: ProtoAclMode) -> Result<Self, TryFromProtoError> {
290 Ok(AclMode::from_bits_retain(proto.acl_mode))
291 }
292}
293
294#[cfg(any(test, feature = "proptest"))]
295impl Arbitrary for AclMode {
296 type Parameters = ();
297 type Strategy = BoxedStrategy<AclMode>;
298
299 fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
300 proptest::bits::BitSetStrategy::masked(AclMode::all().bits())
301 .prop_map(|bits| AclMode::from_bits(bits).expect("invalid proptest implementation"))
302 .boxed()
303 }
304}
305
306#[derive(
313 Debug,
314 Clone,
315 Copy,
316 PartialEq,
317 Eq,
318 PartialOrd,
319 Ord,
320 Serialize,
321 Hash,
322 Deserialize
323)]
324#[cfg_attr(any(test, feature = "proptest"), derive(Arbitrary))]
325pub struct MzAclItem {
326 pub grantee: RoleId,
328 pub grantor: RoleId,
330 pub acl_mode: AclMode,
332}
333
334impl MzAclItem {
335 pub fn empty(grantee: RoleId, grantor: RoleId) -> MzAclItem {
336 MzAclItem {
337 grantee,
338 grantor,
339 acl_mode: AclMode::empty(),
340 }
341 }
342
343 pub fn encode_binary(&self) -> Vec<u8> {
344 let mut res = Vec::with_capacity(Self::binary_size());
345 res.extend_from_slice(&self.grantee.encode_binary());
346 res.extend_from_slice(&self.grantor.encode_binary());
347 res.extend_from_slice(&self.acl_mode.bits().to_le_bytes());
348 res
349 }
350
351 pub fn decode_binary(raw: &[u8]) -> Result<MzAclItem, Error> {
352 if raw.len() != MzAclItem::binary_size() {
353 return Err(anyhow!(
354 "invalid binary size, expecting {}, found {}",
355 MzAclItem::binary_size(),
356 raw.len()
357 ));
358 }
359
360 let role_id_size = RoleId::binary_size();
361
362 let grantee = RoleId::decode_binary(&raw[0..role_id_size])?;
363 let raw = &raw[role_id_size..];
364 let grantor = RoleId::decode_binary(&raw[0..role_id_size])?;
365 let raw = &raw[role_id_size..];
366 let acl_mode = u64::from_le_bytes(raw.try_into()?);
367
368 Ok(MzAclItem {
369 grantee,
370 grantor,
371 acl_mode: AclMode::from_bits_retain(acl_mode),
372 })
373 }
374
375 pub const fn binary_size() -> usize {
376 RoleId::binary_size() + RoleId::binary_size() + size_of::<u64>()
377 }
378}
379
380impl FromStr for MzAclItem {
381 type Err = Error;
382
383 fn from_str(s: &str) -> Result<Self, Self::Err> {
384 let parts: Vec<_> = s.split('=').collect();
385 let &[grantee, rest] = parts.as_slice() else {
386 return Err(anyhow!("invalid mz_aclitem '{s}'"));
387 };
388
389 let parts: Vec<_> = rest.split('/').collect();
390 let &[acl_mode, grantor] = parts.as_slice() else {
391 return Err(anyhow!("invalid mz_aclitem '{s}'"));
392 };
393
394 let grantee: RoleId = if grantee.is_empty() {
395 RoleId::Public
396 } else {
397 grantee.parse()?
398 };
399 let acl_mode: AclMode = acl_mode.parse()?;
400 let grantor: RoleId = grantor.parse()?;
401
402 Ok(MzAclItem {
403 grantee,
404 grantor,
405 acl_mode,
406 })
407 }
408}
409
410impl fmt::Display for MzAclItem {
411 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
412 if !self.grantee.is_public() {
413 write!(f, "{}", self.grantee)?;
414 }
415 write!(f, "={}/{}", self.acl_mode, self.grantor)
416 }
417}
418
419impl RustType<ProtoMzAclItem> for MzAclItem {
420 fn into_proto(&self) -> ProtoMzAclItem {
421 ProtoMzAclItem {
422 grantee: Some(self.grantee.into_proto()),
423 grantor: Some(self.grantor.into_proto()),
424 acl_mode: Some(self.acl_mode.into_proto()),
425 }
426 }
427
428 fn from_proto(proto: ProtoMzAclItem) -> Result<Self, TryFromProtoError> {
429 match (proto.grantee, proto.grantor, proto.acl_mode) {
430 (Some(grantee), Some(grantor), Some(acl_mode)) => Ok(MzAclItem {
431 grantee: RoleId::from_proto(grantee)?,
432 grantor: RoleId::from_proto(grantor)?,
433 acl_mode: AclMode::from_proto(acl_mode)?,
434 }),
435 (None, _, _) => Err(TryFromProtoError::missing_field("ProtoMzAclItem::grantee")),
436 (_, None, _) => Err(TryFromProtoError::missing_field("ProtoMzAclItem::grantor")),
437 (_, _, None) => Err(TryFromProtoError::missing_field("ProtoMzAclItem::acl_mode")),
438 }
439 }
440}
441
442#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
446pub struct PackedMzAclItem([u8; Self::SIZE]);
447
448impl PackedMzAclItem {
449 pub const SYSTEM_TAG: u32 = 100;
458 pub const PREDEFINED_TAG: u32 = 200;
459 pub const USER_TAG: u32 = 300;
460 pub const PUBLIC_TAG: u32 = 400;
461
462 #[inline]
463 fn encode_role(buf: &mut [u8], role: RoleId) {
464 soft_assert_no_log!(buf.len() == 12);
465
466 match role {
467 RoleId::System(val) => {
468 buf[..4].copy_from_slice(&Self::SYSTEM_TAG.to_be_bytes());
469 buf[4..].copy_from_slice(&val.to_be_bytes());
470 }
471 RoleId::Predefined(val) => {
472 buf[..4].copy_from_slice(&Self::PREDEFINED_TAG.to_be_bytes());
473 buf[4..].copy_from_slice(&val.to_be_bytes());
474 }
475 RoleId::User(val) => {
476 buf[..4].copy_from_slice(&Self::USER_TAG.to_be_bytes());
477 buf[4..].copy_from_slice(&val.to_be_bytes());
478 }
479 RoleId::Public => {
480 buf[..4].copy_from_slice(&Self::PUBLIC_TAG.to_be_bytes());
481 }
482 }
483 }
484
485 #[inline]
486 fn decode_role(buf: &[u8]) -> RoleId {
487 soft_assert_no_log!(buf.len() == 12);
488
489 let tag: [u8; 4] = buf[..4]
490 .try_into()
491 .expect("PackedMzAclItem should roundtrip");
492 let tag = u32::from_be_bytes(tag);
493
494 let val: [u8; 8] = buf[4..]
495 .try_into()
496 .expect("PackedMzAclItem should roundtrip");
497 let val = u64::from_be_bytes(val);
498
499 match tag {
500 Self::SYSTEM_TAG => RoleId::System(val),
501 Self::PREDEFINED_TAG => RoleId::Predefined(val),
502 Self::USER_TAG => RoleId::User(val),
503 Self::PUBLIC_TAG => RoleId::Public,
504 x => panic!("unrecognized tag {x}"),
505 }
506 }
507}
508
509impl FixedSizeCodec<MzAclItem> for PackedMzAclItem {
510 const SIZE: usize = 32;
511
512 fn as_bytes(&self) -> &[u8] {
513 &self.0
514 }
515
516 fn from_bytes(val: &[u8]) -> Result<Self, String>
517 where
518 Self: Sized,
519 {
520 let buf: [u8; Self::SIZE] = val.try_into().map_err(|_| {
521 format!(
522 "size for PackedMzAclItem is {} bytes, got {}",
523 Self::SIZE,
524 val.len()
525 )
526 })?;
527
528 Ok(PackedMzAclItem(buf))
529 }
530
531 #[inline]
532 fn from_value(value: MzAclItem) -> Self {
533 let mut buf = [0u8; 32];
534
535 Self::encode_role(&mut buf[..12], value.grantee);
536 Self::encode_role(&mut buf[12..24], value.grantor);
537 buf[24..].copy_from_slice(&value.acl_mode.bits().to_be_bytes());
538
539 PackedMzAclItem(buf)
540 }
541
542 #[inline]
543 fn into_value(self) -> MzAclItem {
544 let grantee = PackedMzAclItem::decode_role(&self.0[..12]);
545 let grantor = PackedMzAclItem::decode_role(&self.0[12..24]);
546
547 let acl_mode: [u8; 8] = self.0[24..]
548 .try_into()
549 .expect("PackedMzAclItem should roundtrip");
550 let acl_mode = AclMode::from_bits(u64::from_be_bytes(acl_mode))
551 .expect("PackedMzAclItem should roundtrip");
552
553 MzAclItem {
554 grantee,
555 grantor,
556 acl_mode,
557 }
558 }
559}
560
561#[derive(
567 Debug,
568 Clone,
569 Copy,
570 PartialEq,
571 Eq,
572 PartialOrd,
573 Ord,
574 Serialize,
575 Hash,
576 Deserialize
577)]
578#[cfg_attr(any(test, feature = "proptest"), derive(Arbitrary))]
579pub struct AclItem {
580 pub grantee: Oid,
582 pub grantor: Oid,
584 pub acl_mode: AclMode,
586}
587
588impl AclItem {
589 pub fn empty(grantee: Oid, grantor: Oid) -> AclItem {
590 AclItem {
591 grantee,
592 grantor,
593 acl_mode: AclMode::empty(),
594 }
595 }
596}
597
598impl AclItem {
602 pub fn encode_binary(&self) -> Vec<u8> {
603 let mut res = Vec::with_capacity(Self::binary_size());
604 res.extend_from_slice(&self.grantee.0.to_le_bytes());
605 res.extend_from_slice(&self.grantor.0.to_le_bytes());
606 res.extend_from_slice(&self.acl_mode.bits().to_le_bytes());
607 res
608 }
609
610 pub fn decode_binary(raw: &[u8]) -> Result<AclItem, Error> {
611 if raw.len() != AclItem::binary_size() {
612 return Err(anyhow!(
613 "invalid binary size, expecting {}, found {}",
614 AclItem::binary_size(),
615 raw.len()
616 ));
617 }
618
619 let oid_size = size_of::<u32>();
620
621 let grantee = Oid(u32::from_le_bytes(raw[0..oid_size].try_into()?));
622 let raw = &raw[oid_size..];
623 let grantor = Oid(u32::from_le_bytes(raw[0..oid_size].try_into()?));
624 let raw = &raw[oid_size..];
625 let acl_mode = u64::from_le_bytes(raw.try_into()?);
626
627 Ok(AclItem {
628 grantee,
629 grantor,
630 acl_mode: AclMode::from_bits_retain(acl_mode),
631 })
632 }
633
634 pub const fn binary_size() -> usize {
635 size_of::<u32>() + size_of::<u32>() + size_of::<u64>()
636 }
637}
638
639impl FromStr for AclItem {
640 type Err = Error;
641
642 fn from_str(s: &str) -> Result<Self, Self::Err> {
651 let parts: Vec<_> = s.split('=').collect();
652 let &[grantee, rest] = parts.as_slice() else {
653 return Err(anyhow!("invalid aclitem '{s}'"));
654 };
655
656 let parts: Vec<_> = rest.split('/').collect();
657 let &[acl_mode, grantor] = parts.as_slice() else {
658 return Err(anyhow!("invalid mz_aclitem '{s}'"));
659 };
660
661 let grantee: Oid = if grantee.is_empty() {
662 PUBLIC_ROLE_OID
663 } else {
664 Oid(grantee.parse()?)
665 };
666 let acl_mode: AclMode = acl_mode.parse()?;
667 let grantor: Oid = Oid(grantor.parse()?);
668
669 Ok(AclItem {
670 grantee,
671 grantor,
672 acl_mode,
673 })
674 }
675}
676
677impl fmt::Display for AclItem {
678 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
679 if self.grantee != PUBLIC_ROLE_OID {
680 write!(f, "{}", self.grantee.0)?;
681 }
682 write!(f, "={}/{}", self.acl_mode, self.grantor.0)
683 }
684}
685
686impl RustType<ProtoAclItem> for AclItem {
687 fn into_proto(&self) -> ProtoAclItem {
688 ProtoAclItem {
689 grantee: self.grantee.0,
690 grantor: self.grantor.0,
691 acl_mode: Some(self.acl_mode.into_proto()),
692 }
693 }
694
695 fn from_proto(proto: ProtoAclItem) -> Result<Self, TryFromProtoError> {
696 match proto.acl_mode {
697 Some(acl_mode) => Ok(AclItem {
698 grantee: Oid(proto.grantee),
699 grantor: Oid(proto.grantor),
700 acl_mode: AclMode::from_proto(acl_mode)?,
701 }),
702 None => Err(TryFromProtoError::missing_field("ProtoMzAclItem::acl_mode")),
703 }
704 }
705}
706
707#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
711pub struct PackedAclItem([u8; Self::SIZE]);
712
713impl FixedSizeCodec<AclItem> for PackedAclItem {
714 const SIZE: usize = 16;
715
716 fn as_bytes(&self) -> &[u8] {
717 &self.0
718 }
719
720 fn from_bytes(slice: &[u8]) -> Result<Self, String> {
721 let buf: [u8; Self::SIZE] = slice.try_into().map_err(|_| {
722 format!(
723 "size for PackedAclItem is {} bytes, got {}",
724 Self::SIZE,
725 slice.len()
726 )
727 })?;
728 Ok(PackedAclItem(buf))
729 }
730
731 #[inline]
732 fn from_value(value: AclItem) -> Self {
733 let mut buf = [0u8; 16];
734
735 buf[..4].copy_from_slice(&value.grantee.0.to_be_bytes());
736 buf[4..8].copy_from_slice(&value.grantor.0.to_be_bytes());
737 buf[8..].copy_from_slice(&value.acl_mode.bits().to_be_bytes());
738
739 PackedAclItem(buf)
740 }
741
742 #[inline]
743 fn into_value(self) -> AclItem {
744 let mut grantee = [0; 4];
745 grantee.copy_from_slice(&self.0[..4]);
746
747 let mut grantor = [0; 4];
748 grantor.copy_from_slice(&self.0[4..8]);
749
750 let mut acl_mode = [0; 8];
751 acl_mode.copy_from_slice(&self.0[8..]);
752 let acl_mode = AclMode::from_bits(u64::from_be_bytes(acl_mode))
753 .expect("PackedAclItem should roundtrip");
754
755 AclItem {
756 grantee: Oid(u32::from_be_bytes(grantee)),
757 grantor: Oid(u32::from_be_bytes(grantor)),
758 acl_mode,
759 }
760 }
761}
762
763#[derive(
765 Debug,
766 Clone,
767 PartialEq,
768 Eq,
769 PartialOrd,
770 Ord,
771 Hash,
772 Deserialize,
773 Serialize
774)]
775pub struct PrivilegeMap(
776 #[serde(serialize_with = "mz_ore::serde::map_key_to_string")] BTreeMap<RoleId, Vec<MzAclItem>>,
777);
778
779impl PrivilegeMap {
780 pub fn new() -> PrivilegeMap {
782 PrivilegeMap(BTreeMap::new())
783 }
784
785 pub fn from_mz_acl_items(items: impl IntoIterator<Item = MzAclItem>) -> PrivilegeMap {
787 let mut map = PrivilegeMap::new();
788 map.grant_all(items);
789 map
790 }
791
792 pub fn get_acl_item(&self, grantee: &RoleId, grantor: &RoleId) -> Option<&MzAclItem> {
794 self.0.get(grantee).and_then(|privileges| {
795 privileges
796 .into_iter()
797 .find(|mz_acl_item| &mz_acl_item.grantor == grantor)
798 })
799 }
800
801 pub fn get_acl_items_for_grantee(&self, grantee: &RoleId) -> impl Iterator<Item = &MzAclItem> {
803 self.0
804 .get(grantee)
805 .into_iter()
806 .flat_map(|privileges| privileges.into_iter())
807 }
808
809 pub fn all_values(&self) -> impl Iterator<Item = &MzAclItem> {
811 self.0
812 .values()
813 .flat_map(|privileges| privileges.into_iter())
814 }
815
816 pub fn all_values_owned(&self) -> impl Iterator<Item = MzAclItem> + '_ {
818 self.all_values().cloned()
819 }
820
821 pub fn into_all_values(self) -> impl Iterator<Item = MzAclItem> {
823 self.0
824 .into_values()
825 .flat_map(|privileges| privileges.into_iter())
826 }
827
828 pub fn grant(&mut self, privilege: MzAclItem) {
830 let grantee_privileges = self.0.entry(privilege.grantee).or_default();
831 if let Some(existing_privilege) = grantee_privileges
832 .iter_mut()
833 .find(|cur_privilege| cur_privilege.grantor == privilege.grantor)
834 {
835 assert_eq!(
837 privilege.grantee, existing_privilege.grantee,
838 "PrivilegeMap out of sync"
839 );
840 existing_privilege.acl_mode = existing_privilege.acl_mode.union(privilege.acl_mode);
841 } else {
842 grantee_privileges.push(privilege);
843 }
844 }
845
846 pub fn grant_all(&mut self, mz_acl_items: impl IntoIterator<Item = MzAclItem>) {
848 for mz_acl_item in mz_acl_items {
849 self.grant(mz_acl_item);
850 }
851 }
852
853 pub fn revoke(&mut self, privilege: &MzAclItem) {
855 let grantee_privileges = self.0.entry(privilege.grantee).or_default();
856 if let Some(existing_privilege) = grantee_privileges
857 .iter_mut()
858 .find(|cur_privilege| cur_privilege.grantor == privilege.grantor)
859 {
860 assert_eq!(
862 privilege.grantee, existing_privilege.grantee,
863 "PrivilegeMap out of sync"
864 );
865 existing_privilege.acl_mode =
866 existing_privilege.acl_mode.difference(privilege.acl_mode);
867 }
868
869 grantee_privileges.retain(|privilege| !privilege.acl_mode.is_empty());
871 if grantee_privileges.is_empty() {
872 self.0.remove(&privilege.grantee);
873 }
874 }
875
876 pub fn debug_json(&self) -> serde_json::Value {
879 let privileges_by_str: BTreeMap<String, _> = self
880 .0
881 .iter()
882 .map(|(key, value)| (key.to_string(), value))
883 .collect();
884 serde_json::json!(privileges_by_str)
885 }
886}
887
888impl Default for PrivilegeMap {
889 fn default() -> PrivilegeMap {
890 PrivilegeMap::new()
891 }
892}
893
894pub fn merge_mz_acl_items(
896 mz_acl_items: impl Iterator<Item = MzAclItem>,
897) -> impl Iterator<Item = MzAclItem> {
898 mz_acl_items
899 .fold(BTreeMap::new(), |mut accum, mz_acl_item| {
900 let item = accum
901 .entry((mz_acl_item.grantee, mz_acl_item.grantor))
902 .or_insert_with(|| MzAclItem::empty(mz_acl_item.grantee, mz_acl_item.grantor));
903 item.acl_mode |= mz_acl_item.acl_mode;
904 accum
905 })
906 .into_values()
907}
908
909#[mz_ore::test]
910fn test_mz_acl_parsing() {
911 let s = "u42=rw/s666";
912 let mz_acl: MzAclItem = s.parse().unwrap();
913 assert_eq!(RoleId::User(42), mz_acl.grantee);
914 assert_eq!(RoleId::System(666), mz_acl.grantor);
915 assert!(!mz_acl.acl_mode.contains(AclMode::INSERT));
916 assert!(mz_acl.acl_mode.contains(AclMode::SELECT));
917 assert!(mz_acl.acl_mode.contains(AclMode::UPDATE));
918 assert!(!mz_acl.acl_mode.contains(AclMode::DELETE));
919 assert!(!mz_acl.acl_mode.contains(AclMode::USAGE));
920 assert!(!mz_acl.acl_mode.contains(AclMode::CREATE));
921 assert!(!mz_acl.acl_mode.contains(AclMode::CREATE_ROLE));
922 assert!(!mz_acl.acl_mode.contains(AclMode::CREATE_DB));
923 assert!(!mz_acl.acl_mode.contains(AclMode::CREATE_CLUSTER));
924 assert!(!mz_acl.acl_mode.contains(AclMode::CREATE_NETWORK_POLICY));
925 assert_eq!(s, mz_acl.to_string());
926
927 let s = "=UC/u4";
928 let mz_acl: MzAclItem = s.parse().unwrap();
929 assert_eq!(RoleId::Public, mz_acl.grantee);
930 assert_eq!(RoleId::User(4), mz_acl.grantor);
931 assert!(!mz_acl.acl_mode.contains(AclMode::INSERT));
932 assert!(!mz_acl.acl_mode.contains(AclMode::SELECT));
933 assert!(!mz_acl.acl_mode.contains(AclMode::UPDATE));
934 assert!(!mz_acl.acl_mode.contains(AclMode::DELETE));
935 assert!(mz_acl.acl_mode.contains(AclMode::USAGE));
936 assert!(mz_acl.acl_mode.contains(AclMode::CREATE));
937 assert!(!mz_acl.acl_mode.contains(AclMode::CREATE_ROLE));
938 assert!(!mz_acl.acl_mode.contains(AclMode::CREATE_DB));
939 assert!(!mz_acl.acl_mode.contains(AclMode::CREATE_CLUSTER));
940 assert!(!mz_acl.acl_mode.contains(AclMode::CREATE_NETWORK_POLICY));
941 assert_eq!(s, mz_acl.to_string());
942
943 let s = "s7=/s12";
944 let mz_acl: MzAclItem = s.parse().unwrap();
945 assert_eq!(RoleId::System(7), mz_acl.grantee);
946 assert_eq!(RoleId::System(12), mz_acl.grantor);
947 assert!(!mz_acl.acl_mode.contains(AclMode::INSERT));
948 assert!(!mz_acl.acl_mode.contains(AclMode::SELECT));
949 assert!(!mz_acl.acl_mode.contains(AclMode::UPDATE));
950 assert!(!mz_acl.acl_mode.contains(AclMode::DELETE));
951 assert!(!mz_acl.acl_mode.contains(AclMode::USAGE));
952 assert!(!mz_acl.acl_mode.contains(AclMode::CREATE));
953 assert!(!mz_acl.acl_mode.contains(AclMode::CREATE_ROLE));
954 assert!(!mz_acl.acl_mode.contains(AclMode::CREATE_DB));
955 assert!(!mz_acl.acl_mode.contains(AclMode::CREATE_CLUSTER));
956 assert!(!mz_acl.acl_mode.contains(AclMode::CREATE_NETWORK_POLICY));
957 assert_eq!(s, mz_acl.to_string());
958
959 let s = "=/u100";
960 let mz_acl: MzAclItem = s.parse().unwrap();
961 assert_eq!(RoleId::Public, mz_acl.grantee);
962 assert_eq!(RoleId::User(100), mz_acl.grantor);
963 assert!(!mz_acl.acl_mode.contains(AclMode::INSERT));
964 assert!(!mz_acl.acl_mode.contains(AclMode::SELECT));
965 assert!(!mz_acl.acl_mode.contains(AclMode::UPDATE));
966 assert!(!mz_acl.acl_mode.contains(AclMode::DELETE));
967 assert!(!mz_acl.acl_mode.contains(AclMode::USAGE));
968 assert!(!mz_acl.acl_mode.contains(AclMode::CREATE));
969 assert!(!mz_acl.acl_mode.contains(AclMode::CREATE_ROLE));
970 assert!(!mz_acl.acl_mode.contains(AclMode::CREATE_DB));
971 assert!(!mz_acl.acl_mode.contains(AclMode::CREATE_CLUSTER));
972 assert!(!mz_acl.acl_mode.contains(AclMode::CREATE_NETWORK_POLICY));
973 assert_eq!(s, mz_acl.to_string());
974
975 let s = "u1=RBNP/u2";
976 let mz_acl: MzAclItem = s.parse().unwrap();
977 assert_eq!(RoleId::User(1), mz_acl.grantee);
978 assert_eq!(RoleId::User(2), mz_acl.grantor);
979 assert!(!mz_acl.acl_mode.contains(AclMode::INSERT));
980 assert!(!mz_acl.acl_mode.contains(AclMode::SELECT));
981 assert!(!mz_acl.acl_mode.contains(AclMode::UPDATE));
982 assert!(!mz_acl.acl_mode.contains(AclMode::DELETE));
983 assert!(!mz_acl.acl_mode.contains(AclMode::USAGE));
984 assert!(!mz_acl.acl_mode.contains(AclMode::CREATE));
985 assert!(mz_acl.acl_mode.contains(AclMode::CREATE_ROLE));
986 assert!(mz_acl.acl_mode.contains(AclMode::CREATE_DB));
987 assert!(mz_acl.acl_mode.contains(AclMode::CREATE_CLUSTER));
988 assert!(mz_acl.acl_mode.contains(AclMode::CREATE_NETWORK_POLICY));
989 assert_eq!(s, mz_acl.to_string());
990
991 mz_ore::assert_err!("u42/rw=u666".parse::<MzAclItem>());
992 mz_ore::assert_err!("u32=C/".parse::<MzAclItem>());
993 mz_ore::assert_err!("=/".parse::<MzAclItem>());
994 mz_ore::assert_err!("f62hfiuew827fhh".parse::<MzAclItem>());
995 mz_ore::assert_err!("u2=rw/s66=CU/u33".parse::<MzAclItem>());
996}
997
998#[mz_ore::test]
999fn test_mz_acl_item_binary() {
1000 use std::ops::BitAnd;
1001
1002 let mz_acl_item = MzAclItem {
1003 grantee: RoleId::User(42),
1004 grantor: RoleId::System(666),
1005 acl_mode: AclMode::empty()
1006 .bitand(AclMode::SELECT)
1007 .bitand(AclMode::UPDATE),
1008 };
1009 assert_eq!(
1010 mz_acl_item,
1011 MzAclItem::decode_binary(&mz_acl_item.encode_binary()).unwrap()
1012 );
1013
1014 let mz_acl_item = MzAclItem {
1015 grantee: RoleId::Public,
1016 grantor: RoleId::User(4),
1017 acl_mode: AclMode::empty()
1018 .bitand(AclMode::USAGE)
1019 .bitand(AclMode::CREATE),
1020 };
1021 assert_eq!(
1022 mz_acl_item,
1023 MzAclItem::decode_binary(&mz_acl_item.encode_binary()).unwrap()
1024 );
1025
1026 let mz_acl_item = MzAclItem {
1027 grantee: RoleId::System(7),
1028 grantor: RoleId::System(12),
1029 acl_mode: AclMode::empty(),
1030 };
1031 assert_eq!(
1032 mz_acl_item,
1033 MzAclItem::decode_binary(&mz_acl_item.encode_binary()).unwrap()
1034 );
1035
1036 let mz_acl_item = MzAclItem {
1037 grantee: RoleId::Public,
1038 grantor: RoleId::User(100),
1039 acl_mode: AclMode::empty(),
1040 };
1041 assert_eq!(
1042 mz_acl_item,
1043 MzAclItem::decode_binary(&mz_acl_item.encode_binary()).unwrap()
1044 );
1045
1046 mz_ore::assert_err!(MzAclItem::decode_binary(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 0]))
1047}
1048
1049#[mz_ore::test]
1050fn test_mz_acl_item_binary_size() {
1051 assert_eq!(26, MzAclItem::binary_size());
1052}
1053
1054#[mz_ore::test]
1055fn test_acl_mode_serde_and_debug() {
1056 let acl_mode = AclMode::INSERT | AclMode::SELECT;
1057 let json = serde_json::to_string(&acl_mode).unwrap();
1058 assert_eq!(json, r#"{"bits":3}"#);
1059 assert_eq!(serde_json::from_str::<AclMode>(&json).unwrap(), acl_mode);
1060
1061 assert_eq!(format!("{acl_mode:?}"), "INSERT | SELECT");
1062 assert_eq!(format!("{:?}", AclMode::empty()), "(empty)");
1063}
1064
1065#[mz_ore::test]
1066fn test_acl_parsing() {
1067 let s = "42=rw/666";
1068 let acl: AclItem = s.parse().unwrap();
1069 assert_eq!(42, acl.grantee.0);
1070 assert_eq!(666, acl.grantor.0);
1071 assert!(!acl.acl_mode.contains(AclMode::INSERT));
1072 assert!(acl.acl_mode.contains(AclMode::SELECT));
1073 assert!(acl.acl_mode.contains(AclMode::UPDATE));
1074 assert!(!acl.acl_mode.contains(AclMode::DELETE));
1075 assert!(!acl.acl_mode.contains(AclMode::USAGE));
1076 assert!(!acl.acl_mode.contains(AclMode::CREATE));
1077 assert!(!acl.acl_mode.contains(AclMode::CREATE_ROLE));
1078 assert!(!acl.acl_mode.contains(AclMode::CREATE_DB));
1079 assert!(!acl.acl_mode.contains(AclMode::CREATE_CLUSTER));
1080 assert!(!acl.acl_mode.contains(AclMode::CREATE_NETWORK_POLICY));
1081 assert_eq!(s, acl.to_string());
1082
1083 let s = "=UC/4";
1084 let acl: AclItem = s.parse().unwrap();
1085 assert_eq!(PUBLIC_ROLE_OID, acl.grantee);
1086 assert_eq!(4, acl.grantor.0);
1087 assert!(!acl.acl_mode.contains(AclMode::INSERT));
1088 assert!(!acl.acl_mode.contains(AclMode::SELECT));
1089 assert!(!acl.acl_mode.contains(AclMode::UPDATE));
1090 assert!(!acl.acl_mode.contains(AclMode::DELETE));
1091 assert!(acl.acl_mode.contains(AclMode::USAGE));
1092 assert!(acl.acl_mode.contains(AclMode::CREATE));
1093 assert!(!acl.acl_mode.contains(AclMode::CREATE_ROLE));
1094 assert!(!acl.acl_mode.contains(AclMode::CREATE_DB));
1095 assert!(!acl.acl_mode.contains(AclMode::CREATE_CLUSTER));
1096 assert!(!acl.acl_mode.contains(AclMode::CREATE_NETWORK_POLICY));
1097 assert_eq!(s, acl.to_string());
1098
1099 let s = "7=/12";
1100 let acl: AclItem = s.parse().unwrap();
1101 assert_eq!(7, acl.grantee.0);
1102 assert_eq!(12, acl.grantor.0);
1103 assert!(!acl.acl_mode.contains(AclMode::INSERT));
1104 assert!(!acl.acl_mode.contains(AclMode::SELECT));
1105 assert!(!acl.acl_mode.contains(AclMode::UPDATE));
1106 assert!(!acl.acl_mode.contains(AclMode::DELETE));
1107 assert!(!acl.acl_mode.contains(AclMode::USAGE));
1108 assert!(!acl.acl_mode.contains(AclMode::CREATE));
1109 assert!(!acl.acl_mode.contains(AclMode::CREATE_ROLE));
1110 assert!(!acl.acl_mode.contains(AclMode::CREATE_DB));
1111 assert!(!acl.acl_mode.contains(AclMode::CREATE_CLUSTER));
1112 assert!(!acl.acl_mode.contains(AclMode::CREATE_NETWORK_POLICY));
1113 assert_eq!(s, acl.to_string());
1114
1115 let s = "=/100";
1116 let acl: AclItem = s.parse().unwrap();
1117 assert_eq!(PUBLIC_ROLE_OID, acl.grantee);
1118 assert_eq!(100, acl.grantor.0);
1119 assert!(!acl.acl_mode.contains(AclMode::INSERT));
1120 assert!(!acl.acl_mode.contains(AclMode::SELECT));
1121 assert!(!acl.acl_mode.contains(AclMode::UPDATE));
1122 assert!(!acl.acl_mode.contains(AclMode::DELETE));
1123 assert!(!acl.acl_mode.contains(AclMode::USAGE));
1124 assert!(!acl.acl_mode.contains(AclMode::CREATE));
1125 assert!(!acl.acl_mode.contains(AclMode::CREATE_ROLE));
1126 assert!(!acl.acl_mode.contains(AclMode::CREATE_DB));
1127 assert!(!acl.acl_mode.contains(AclMode::CREATE_CLUSTER));
1128 assert!(!acl.acl_mode.contains(AclMode::CREATE_NETWORK_POLICY));
1129 assert_eq!(s, acl.to_string());
1130
1131 let s = "1=RBNP/2";
1132 let acl: AclItem = s.parse().unwrap();
1133 assert_eq!(1, acl.grantee.0);
1134 assert_eq!(2, acl.grantor.0);
1135 assert!(!acl.acl_mode.contains(AclMode::INSERT));
1136 assert!(!acl.acl_mode.contains(AclMode::SELECT));
1137 assert!(!acl.acl_mode.contains(AclMode::UPDATE));
1138 assert!(!acl.acl_mode.contains(AclMode::DELETE));
1139 assert!(!acl.acl_mode.contains(AclMode::USAGE));
1140 assert!(!acl.acl_mode.contains(AclMode::CREATE));
1141 assert!(acl.acl_mode.contains(AclMode::CREATE_ROLE));
1142 assert!(acl.acl_mode.contains(AclMode::CREATE_DB));
1143 assert!(acl.acl_mode.contains(AclMode::CREATE_CLUSTER));
1144 assert!(acl.acl_mode.contains(AclMode::CREATE_NETWORK_POLICY));
1145 assert_eq!(s, acl.to_string());
1146
1147 mz_ore::assert_err!("42/rw=666".parse::<AclItem>());
1148 mz_ore::assert_err!("u42=rw/u666".parse::<AclItem>());
1149 mz_ore::assert_err!("s42=rw/s666".parse::<AclItem>());
1150 mz_ore::assert_err!("u32=C/".parse::<AclItem>());
1151 mz_ore::assert_err!("=/".parse::<AclItem>());
1152 mz_ore::assert_err!("f62hfiuew827fhh".parse::<AclItem>());
1153 mz_ore::assert_err!("u2=rw/s66=CU/u33".parse::<AclItem>());
1154}
1155
1156#[mz_ore::test]
1157fn test_acl_item_binary() {
1158 use std::ops::BitAnd;
1159
1160 let acl_item = AclItem {
1161 grantee: Oid(42),
1162 grantor: Oid(666),
1163 acl_mode: AclMode::empty()
1164 .bitand(AclMode::SELECT)
1165 .bitand(AclMode::UPDATE),
1166 };
1167 assert_eq!(
1168 acl_item,
1169 AclItem::decode_binary(&acl_item.encode_binary()).unwrap()
1170 );
1171
1172 let acl_item = AclItem {
1173 grantee: PUBLIC_ROLE_OID,
1174 grantor: Oid(4),
1175 acl_mode: AclMode::empty()
1176 .bitand(AclMode::USAGE)
1177 .bitand(AclMode::CREATE),
1178 };
1179 assert_eq!(
1180 acl_item,
1181 AclItem::decode_binary(&acl_item.encode_binary()).unwrap()
1182 );
1183
1184 let acl_item = AclItem {
1185 grantee: Oid(7),
1186 grantor: Oid(12),
1187 acl_mode: AclMode::empty(),
1188 };
1189 assert_eq!(
1190 acl_item,
1191 AclItem::decode_binary(&acl_item.encode_binary()).unwrap()
1192 );
1193
1194 let acl_item = AclItem {
1195 grantee: PUBLIC_ROLE_OID,
1196 grantor: Oid(100),
1197 acl_mode: AclMode::empty(),
1198 };
1199 assert_eq!(
1200 acl_item,
1201 AclItem::decode_binary(&acl_item.encode_binary()).unwrap()
1202 );
1203
1204 mz_ore::assert_err!(AclItem::decode_binary(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 0]))
1205}
1206
1207#[mz_ore::test]
1208fn test_acl_item_binary_size() {
1209 assert_eq!(16, AclItem::binary_size());
1210}
1211
1212#[cfg(test)]
1213proptest! {
1214 #[mz_ore::test]
1215 #[cfg_attr(miri, ignore)] fn proptest_acl_item_binary_encoding_roundtrip(acl_item: AclItem) {
1217 let encoded = acl_item.encode_binary();
1218 let decoded = AclItem::decode_binary(&encoded).unwrap();
1219 assert_eq!(acl_item, decoded);
1220 }
1221
1222 #[mz_ore::test]
1223 #[cfg_attr(miri, ignore)] fn proptest_valid_acl_item_str(acl_item: AclItem) {
1225 let encoded = acl_item.to_string();
1226 let decoded = AclItem::from_str(&encoded).unwrap();
1227 assert_eq!(acl_item, decoded);
1228 }
1229}
1230
1231#[mz_ore::test]
1232#[cfg(any(test, feature = "proptest"))]
1233fn proptest_packed_acl_item_roundtrips() {
1234 fn roundtrip_acl_item(og: AclItem) {
1235 let packed = PackedAclItem::from_value(og);
1236 let rnd = packed.into_value();
1237 assert_eq!(og, rnd);
1238 }
1239
1240 proptest!(|(acl_item in proptest::arbitrary::any::<AclItem>())| {
1241 roundtrip_acl_item(acl_item);
1242 })
1243}
1244
1245#[mz_ore::test]
1246#[cfg_attr(miri, ignore)] #[cfg(any(test, feature = "proptest"))]
1248fn proptest_packed_acl_item_sorts() {
1249 fn sort_acl_items(mut og: Vec<AclItem>) {
1250 let mut packed: Vec<_> = og.iter().copied().map(PackedAclItem::from_value).collect();
1251
1252 og.sort();
1253 packed.sort();
1254
1255 let rnd: Vec<_> = packed.into_iter().map(PackedAclItem::into_value).collect();
1256 assert_eq!(og, rnd);
1257 }
1258
1259 proptest!(|(acl_items in proptest::collection::vec(any::<AclItem>(), 0..64))| {
1260 sort_acl_items(acl_items);
1261 });
1262}
1263
1264#[mz_ore::test]
1265#[cfg(any(test, feature = "proptest"))]
1266fn proptest_packed_mz_acl_item_roundtrips() {
1267 fn roundtrip_mz_acl_item(og: MzAclItem) {
1268 let packed = PackedMzAclItem::from_value(og);
1269 let rnd = packed.into_value();
1270 assert_eq!(og, rnd);
1271 }
1272
1273 proptest!(|(acl_item in proptest::arbitrary::any::<MzAclItem>())| {
1274 roundtrip_mz_acl_item(acl_item);
1275 })
1276}
1277
1278#[mz_ore::test]
1279#[cfg_attr(miri, ignore)] #[cfg(any(test, feature = "proptest"))]
1281fn proptest_packed_mz_acl_item_sorts() {
1282 fn sort_mz_acl_items(mut og: Vec<MzAclItem>) {
1283 let mut packed: Vec<_> = og
1284 .iter()
1285 .copied()
1286 .map(PackedMzAclItem::from_value)
1287 .collect();
1288
1289 og.sort();
1290 packed.sort();
1291
1292 let rnd: Vec<_> = packed
1293 .into_iter()
1294 .map(PackedMzAclItem::into_value)
1295 .collect();
1296 assert_eq!(og, rnd);
1297 }
1298
1299 proptest!(|(acl_items in proptest::collection::vec(any::<MzAclItem>(), 0..64))| {
1300 sort_mz_acl_items(acl_items);
1301 });
1302}