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