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