1use derive_more::Display;
2use std::{
3 any::type_name,
4 fmt::{self, Debug},
5 ops::{BitAnd, BitOr},
6};
7
8use super::Role;
9use crate::claims::common::ScalarOrArray;
10use serde::{Deserialize, Serialize};
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Display)]
14#[display("{_0}")]
15pub struct Scope(PermissionFlags);
16
17impl Default for Scope {
18 fn default() -> Self {
21 Self::with_no_permissions()
22 }
23}
24
25#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
29pub struct PermissionFlags(u64);
30
31#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Display)]
35pub enum Permission {
36 #[display("access_key:{_0}")]
37 AccessKey(AccessKeyPermission),
38
39 #[display("dataset:{_0}")]
40 Keyset(KeysetPermission),
41
42 #[display("client:{_0}")]
43 Client(ClientPermission),
44
45 #[display("data_key:{_0}")]
46 DataKey(DataKeyPermission),
47
48 #[display("cs_support:{_0}")]
49 Support(SupportPermission),
50
51 #[display("logging:{_0}")]
52 Logging(LoggingPermission),
53
54 #[display("actor:{_0}")]
55 Actor(ActorPermission),
56}
57
58#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Display)]
62#[repr(u8)]
63pub enum SupportPermission {
64 #[display("admin")]
65 Admin = 0b0000_0001,
66}
67
68#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Display)]
72#[repr(u8)]
73pub enum LoggingPermission {
74 #[display("append")]
75 Append = 0b0000_0001,
76}
77
78#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Display)]
80#[repr(u8)]
81pub enum AccessKeyPermission {
82 #[display("create")]
84 Create = 0b0000_0001,
85
86 #[display("list")]
88 List = 0b0000_0010,
89
90 #[display("delete")]
92 Delete = 0b0000_0100,
93}
94
95#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Display)]
97#[repr(u8)]
98pub enum KeysetPermission {
99 #[display("create")]
101 Create = 0b0000_0001,
102
103 #[display("list")]
105 List = 0b0000_0010,
106
107 #[display("disable")]
109 Disable = 0b0000_0100,
110
111 #[display("enable")]
113 Enable = 0b0000_1000,
114
115 #[display("grant")]
117 Grant = 0b0001_0000,
118
119 #[display("modify")]
121 Modify = 0b0010_0000,
122
123 #[display("revoke")]
125 Revoke = 0b0100_0000,
126}
127
128#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Display)]
130#[repr(u8)]
131pub enum ClientPermission {
132 #[display("create")]
134 Create = 0b0000_0001,
135
136 #[display("list")]
138 List = 0b0000_0010,
139
140 #[display("delete")]
142 Delete = 0b0000_0100,
143}
144
145#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Display)]
147#[repr(u8)]
148pub enum DataKeyPermission {
149 #[display("generate")]
151 Generate = 0b0000_0001,
152
153 #[display("retrieve")]
155 Retrieve = 0b0000_0010,
156}
157
158#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Display)]
160#[repr(u8)]
161pub enum ActorPermission {
162 #[display("create")]
164 Create = 0b0000_0001,
165
166 #[display("list")]
168 List = 0b0000_0010,
169
170 #[display("delete")]
172 Delete = 0b0000_0100,
173}
174
175impl Permission {
176 fn parse(input: &str) -> Option<Self> {
180 match input {
181 s if s.starts_with("keyset:") => Some(Self::Keyset(KeysetPermission::parse(
182 &s["keyset:".len()..],
183 )?)),
184 s if s.starts_with("access_key:") => Some(Self::AccessKey(AccessKeyPermission::parse(
185 &s["access_key:".len()..],
186 )?)),
187 s if s.starts_with("dataset:") => Some(Self::Keyset(KeysetPermission::parse(
189 &s["dataset:".len()..],
190 )?)),
191 s if s.starts_with("data_key:") => Some(Self::DataKey(DataKeyPermission::parse(
192 &s["data_key:".len()..],
193 )?)),
194 s if s.starts_with("client:") => Some(Self::Client(ClientPermission::parse(
195 &s["client:".len()..],
196 )?)),
197 s if s.starts_with("cs_support:") => Some(Self::Support(SupportPermission::parse(
198 &s["cs_support:".len()..],
199 )?)),
200 s if s.starts_with("logging:") => Some(Self::Logging(LoggingPermission::parse(
201 &s["logging:".len()..],
202 )?)),
203 s if s.starts_with("actor:") => {
204 Some(Self::Actor(ActorPermission::parse(&s["actor:".len()..])?))
205 }
206 _ => None,
207 }
208 }
209
210 const fn to_flags(self) -> PermissionFlags {
212 const _: () = assert!(size_of::<KeysetPermission>() == 1);
216 const _: () = assert!(size_of::<ClientPermission>() == 1);
217 const _: () = assert!(size_of::<DataKeyPermission>() == 1);
218 const _: () = assert!(size_of::<SupportPermission>() == 1);
219 const _: () = assert!(size_of::<LoggingPermission>() == 1);
220 const _: () = assert!(size_of::<AccessKeyPermission>() == 1);
221 const _: () = assert!(size_of::<ActorPermission>() == 1);
222
223 match self {
224 Permission::Keyset(permission) => PermissionFlags(permission as u64),
225 Permission::Client(permission) => PermissionFlags((permission as u64) << 8),
226 Permission::DataKey(permission) => PermissionFlags((permission as u64) << 16),
227 Permission::Support(permission) => PermissionFlags((permission as u64) << 24),
228 Permission::Logging(permission) => PermissionFlags((permission as u64) << 32),
229 Permission::AccessKey(permission) => PermissionFlags((permission as u64) << 40),
230 Permission::Actor(permission) => PermissionFlags((permission as u64) << 48),
231 }
232 }
233
234 const ALL: &[Permission] = &[
236 Self::Keyset(KeysetPermission::Create),
238 Self::Keyset(KeysetPermission::List),
239 Self::Keyset(KeysetPermission::Enable),
240 Self::Keyset(KeysetPermission::Disable),
241 Self::Keyset(KeysetPermission::Grant),
242 Self::Keyset(KeysetPermission::Modify),
243 Self::Keyset(KeysetPermission::Revoke),
244 Self::DataKey(DataKeyPermission::Generate),
246 Self::DataKey(DataKeyPermission::Retrieve),
247 Self::Client(ClientPermission::Create),
249 Self::Client(ClientPermission::List),
250 Self::Client(ClientPermission::Delete),
251 Self::AccessKey(AccessKeyPermission::Create),
253 Self::AccessKey(AccessKeyPermission::List),
254 Self::AccessKey(AccessKeyPermission::Delete),
255 Self::Actor(ActorPermission::Create),
257 Self::Actor(ActorPermission::List),
258 Self::Actor(ActorPermission::Delete),
259 Self::Support(SupportPermission::Admin),
260 Self::Logging(LoggingPermission::Append),
261 ];
262}
263
264macro_rules! impl_from {
265 ($variant:ident, $ty:ty) => {
266 impl From<$ty> for Permission {
267 fn from(value: $ty) -> Self {
268 Self::$variant(value)
269 }
270 }
271 };
272}
273
274impl_from!(AccessKey, AccessKeyPermission);
275impl_from!(Keyset, KeysetPermission);
276impl_from!(DataKey, DataKeyPermission);
277impl_from!(Client, ClientPermission);
278impl_from!(Support, SupportPermission);
279impl_from!(Logging, LoggingPermission);
280impl_from!(Actor, ActorPermission);
281
282impl PermissionFlags {
283 pub const fn empty() -> Self {
285 Self(0)
286 }
287
288 pub const fn with_flag(flag: Permission) -> Self {
290 Self::empty().add(flag)
291 }
292
293 pub const fn add(self, permission: Permission) -> Self {
295 Self(self.0 | permission.to_flags().0)
296 }
297
298 pub const fn merge(self, other: Self) -> Self {
300 Self(self.0 | other.0)
301 }
302
303 fn count_permissions(&self) -> u32 {
305 self.0.count_ones()
306 }
307}
308
309impl IntoIterator for PermissionFlags {
310 type IntoIter = PermissionsIter;
311 type Item = Permission;
312
313 fn into_iter(self) -> Self::IntoIter {
314 PermissionsIter(self, Permission::ALL)
315 }
316}
317
318impl FromIterator<Permission> for PermissionFlags {
319 fn from_iter<T: IntoIterator<Item = Permission>>(iter: T) -> Self {
320 let iter = iter.into_iter();
321 let mut flags = Self(0);
322 for permission in iter {
323 flags = flags.add(permission);
324 }
325 flags
326 }
327}
328
329pub struct PermissionsIter(PermissionFlags, &'static [Permission]);
331
332impl Iterator for PermissionsIter {
333 type Item = Permission;
334
335 fn next(&mut self) -> Option<Self::Item> {
336 loop {
339 if let Some((first, rest)) = self.1.split_first() {
340 self.1 = rest;
342 if self.0 & first.to_flags() == first.to_flags() {
343 return Some(*first);
344 }
345 } else {
346 return None;
348 }
349 }
350 }
351}
352
353impl BitAnd for PermissionFlags {
354 type Output = Self;
355
356 fn bitand(self, rhs: Self) -> Self::Output {
357 Self(self.0 & rhs.0)
358 }
359}
360
361impl BitOr for PermissionFlags {
362 type Output = Self;
363
364 fn bitor(self, rhs: Self) -> Self::Output {
365 Self(self.0 | rhs.0)
366 }
367}
368
369impl fmt::Display for PermissionFlags {
370 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
371 let count = self.count_permissions() as usize;
372
373 for (idx, scope) in self.into_iter().enumerate() {
375 fmt::Display::fmt(&scope, f)?;
376 if idx < count - 1 {
377 fmt::Display::fmt(", ", f)?;
378 }
379 }
380
381 Ok(())
382 }
383}
384
385impl Debug for PermissionFlags {
386 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
387 let count = self.count_permissions() as usize;
388
389 f.write_fmt(format_args!("{}(", type_name::<Self>()))?;
390
391 for (idx, scope) in self.into_iter().enumerate() {
392 fmt::Display::fmt(&scope, f)?;
393 if idx < count - 1 {
394 fmt::Display::fmt("|", f)?;
395 }
396 }
397
398 f.write_str(")")?;
399
400 Ok(())
401 }
402}
403
404impl KeysetPermission {
405 fn parse(input: &str) -> Option<Self> {
406 match input {
407 "create" => Some(Self::Create),
408 "list" => Some(Self::List),
409 "disable" => Some(Self::Disable),
410 "enable" => Some(Self::Enable),
411 "grant" => Some(Self::Grant),
412 "modify" => Some(Self::Modify),
413 "revoke" => Some(Self::Revoke),
414 _ => None,
415 }
416 }
417}
418
419impl ClientPermission {
420 fn parse(input: &str) -> Option<Self> {
421 match input {
422 "create" => Some(Self::Create),
423 "list" => Some(Self::List),
424 "delete" => Some(Self::Delete),
425 _ => None,
426 }
427 }
428}
429
430impl DataKeyPermission {
431 fn parse(input: &str) -> Option<Self> {
432 match input {
433 "generate" => Some(Self::Generate),
434 "retrieve" => Some(Self::Retrieve),
435 _ => None,
436 }
437 }
438}
439
440impl SupportPermission {
441 fn parse(input: &str) -> Option<Self> {
442 match input {
443 "admin" => Some(Self::Admin),
444 _ => None,
445 }
446 }
447}
448
449impl LoggingPermission {
450 fn parse(input: &str) -> Option<Self> {
451 match input {
452 "append" => Some(Self::Append),
453 _ => None,
454 }
455 }
456}
457
458impl AccessKeyPermission {
459 fn parse(input: &str) -> Option<Self> {
460 match input {
461 "create" => Some(Self::Create),
462 "list" => Some(Self::List),
463 "delete" => Some(Self::Delete),
464 _ => None,
465 }
466 }
467}
468
469impl ActorPermission {
470 fn parse(input: &str) -> Option<Self> {
471 match input {
472 "create" => Some(Self::Create),
473 "list" => Some(Self::List),
474 "delete" => Some(Self::Delete),
475 _ => None,
476 }
477 }
478}
479
480impl Scope {
481 pub const fn with_permissions(permissions: PermissionFlags) -> Self {
483 Self(permissions)
484 }
485
486 pub const fn with_permission(permission: Permission) -> Self {
488 Self(PermissionFlags::empty().add(permission))
489 }
490
491 pub fn with_no_permissions() -> Self {
493 Self(PermissionFlags::empty())
494 }
495
496 pub fn merge(self, other: Self) -> Self {
498 Self(self.0 | other.0)
499 }
500
501 pub fn parse(input: &str) -> Self {
504 let permissions: PermissionFlags =
505 input
506 .split_whitespace()
507 .fold(PermissionFlags::empty(), |acc, s| {
508 if let Some(permission) = Permission::parse(s) {
509 acc.add(permission)
510 } else {
511 acc
512 }
513 });
514
515 Self(permissions)
516 }
517
518 pub fn has_permission(&self, permission: Permission) -> bool {
520 self.0 & permission.to_flags() == permission.to_flags()
521 }
522
523 pub fn has_all_permissions(&self, other: Self) -> bool {
525 self.0 & other.0 == other.0
526 }
527
528 pub fn count_permissions(&self) -> u32 {
530 self.0.count_permissions()
531 }
532
533 pub fn permissions(&self) -> impl Iterator<Item = Permission> {
535 self.0.into_iter()
536 }
537}
538
539pub const WORKSPACE_ADMIN_SCOPE: Scope = Scope(
542 PermissionFlags::empty()
543 .add(Permission::AccessKey(AccessKeyPermission::Create))
544 .add(Permission::AccessKey(AccessKeyPermission::List))
545 .add(Permission::AccessKey(AccessKeyPermission::Delete))
546 .add(Permission::Keyset(KeysetPermission::Create))
547 .add(Permission::Keyset(KeysetPermission::List))
548 .add(Permission::Keyset(KeysetPermission::Disable))
549 .add(Permission::Keyset(KeysetPermission::Enable))
550 .add(Permission::Keyset(KeysetPermission::Grant))
551 .add(Permission::Keyset(KeysetPermission::Modify))
552 .add(Permission::Keyset(KeysetPermission::Revoke))
553 .add(Permission::Client(ClientPermission::Create))
554 .add(Permission::Client(ClientPermission::List))
555 .add(Permission::Client(ClientPermission::Delete))
556 .add(Permission::DataKey(DataKeyPermission::Generate))
557 .add(Permission::DataKey(DataKeyPermission::Retrieve))
558 .add(Permission::Actor(ActorPermission::Create))
559 .add(Permission::Actor(ActorPermission::List))
560 .add(Permission::Actor(ActorPermission::Delete)),
561);
562
563pub const WORKSPACE_CONTROL_SCOPE: Scope = Scope(
567 PermissionFlags::empty()
568 .add(Permission::Keyset(KeysetPermission::Create))
569 .add(Permission::Keyset(KeysetPermission::List))
570 .add(Permission::Keyset(KeysetPermission::Disable))
571 .add(Permission::Keyset(KeysetPermission::Enable))
572 .add(Permission::Keyset(KeysetPermission::Grant))
573 .add(Permission::Keyset(KeysetPermission::Modify))
574 .add(Permission::Keyset(KeysetPermission::Revoke))
575 .add(Permission::Client(ClientPermission::List)),
576);
577
578pub const WORKSPACE_MEMBER_SCOPE: Scope = Scope(
581 PermissionFlags::empty()
582 .add(Permission::Keyset(KeysetPermission::List))
583 .add(Permission::Client(ClientPermission::Create))
584 .add(Permission::DataKey(DataKeyPermission::Generate))
585 .add(Permission::DataKey(DataKeyPermission::Retrieve)),
586);
587
588pub const LOGGING_SCOPE: Scope =
589 Scope(PermissionFlags::empty().add(Permission::Logging(LoggingPermission::Append)));
590
591impl From<Option<Role>> for Scope {
592 fn from(role: Option<Role>) -> Self {
593 match role {
594 Some(role) => role.scope(),
595 None => Default::default(),
596 }
597 }
598}
599
600impl From<Vec<String>> for Scope {
601 fn from(scope_names: Vec<String>) -> Self {
602 Scope(
603 scope_names
604 .into_iter()
605 .fold(PermissionFlags::empty(), |acc, s| {
606 if let Some(permission) = Permission::parse(&s) {
607 acc.merge(permission.to_flags())
608 } else {
609 acc
610 }
611 }),
612 )
613 }
614}
615
616impl Serialize for Permission {
617 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
618 where
619 S: serde::Serializer,
620 {
621 self.to_string().serialize(serializer)
622 }
623}
624
625impl Serialize for Scope {
626 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
627 where
628 S: serde::Serializer,
629 {
630 let flags: Vec<Permission> = self.permissions().collect();
631
632 match &flags[..] {
634 &[] => serializer.serialize_none(),
635 &[permission] => Some(ScalarOrArray::Scalar(permission)).serialize(serializer),
636 flags => Some(ScalarOrArray::Array(flags.iter().collect())).serialize(serializer),
637 }
638 }
639}
640
641impl<'de> Deserialize<'de> for Scope {
643 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
644 where
645 D: serde::Deserializer<'de>,
646 {
647 let items: Option<ScalarOrArray<String>> = Deserialize::deserialize(deserializer)?;
648 match items {
649 Some(ScalarOrArray::Array(items)) => Ok(Scope::from(items)),
650 Some(ScalarOrArray::Scalar(item)) => Ok(Scope(
651 Permission::parse(&item)
652 .map(|p| p.to_flags())
653 .unwrap_or(PermissionFlags::empty()),
654 )),
655 None => Ok(Scope::with_no_permissions()),
656 }
657 }
658}
659
660impl From<String> for Scope {
661 fn from(value: String) -> Self {
662 Scope::parse(&value)
663 }
664}
665
666#[cfg(test)]
667mod tests {
668 use super::*;
669 use serde_json::{json, Value};
670
671 mod parse {
672 use super::*;
673
674 #[test]
675 fn empty_string_parses_to_empty_scope() {
676 let scope = Scope::parse("");
677 assert_eq!(scope, Scope::with_no_permissions());
678 }
679
680 #[test]
681 fn single_scope_parses_correctly() {
682 let scope = Scope::parse("dataset:create");
683 assert!(scope.has_permission(Permission::Keyset(KeysetPermission::Create)));
684 assert_eq!(scope.count_permissions(), 1);
685 }
686
687 #[test]
688 fn multiple_scopes_parse_correctly() {
689 let scope = Scope::parse("dataset:create client:list");
690 assert!(scope.has_permission(Permission::Keyset(KeysetPermission::Create)));
691 assert!(scope.has_permission(Permission::Client(ClientPermission::List)));
692 assert_eq!(scope.count_permissions(), 2);
693 }
694 }
695
696 mod serialize {
697 use super::*;
698
699 #[test]
700 fn empty_scope_serializes_as_null() {
701 let scope = Scope::default();
702 let serialized = serde_json::to_value(scope).unwrap();
703 assert_eq!(serialized, Value::Null);
704 }
705
706 #[test]
707 fn single_scope_serializes_as_string() {
708 let scope = Scope::parse("dataset:create");
709 let serialized = serde_json::to_value(scope).unwrap();
710 assert_eq!(serialized, json!("dataset:create"));
711 }
712
713 #[test]
714 fn multiple_scopes_serializes_as_array() {
715 let scope = Scope::parse("dataset:create client:list");
716 let serialized = serde_json::to_value(scope).unwrap();
717
718 assert!(
719 serialized == json!(["dataset:create", "client:list"])
720 || serialized == json!(["client:list", "dataset:create"]),
721 "Expected serialized scope to be an array of scopes, got: {serialized:?}"
722 );
723 }
724 }
725
726 mod deserialize {
727 use super::*;
728
729 #[test]
730 fn empty_scope_deserializes_from_null() {
731 let json = Value::Null;
732 let scope: Scope = serde_json::from_value(json).unwrap();
733 assert_eq!(scope, Scope::default());
734 }
735
736 #[test]
737 fn empty_string_deserializes_to_empty_scope() {
738 let json = json!("");
739 let scope: Scope = serde_json::from_value(json).unwrap();
740 assert_eq!(scope, Scope::default());
741 }
742
743 #[test]
744 fn single_scope_deserializes_from_string() {
745 let json = json!("dataset:create");
746 let scope: Scope = serde_json::from_value(json).unwrap();
747 assert_eq!(scope, Scope::parse("dataset:create"));
748 }
749
750 #[test]
751 fn multiple_scopes_deserialize_from_array() {
752 let json = json!(["dataset:create", "client:list"]);
753 let scope: Scope = serde_json::from_value(json).unwrap();
754 assert!(scope.has_permission(Permission::Keyset(KeysetPermission::Create)));
755 assert!(scope.has_permission(Permission::Client(ClientPermission::List)));
756 assert_eq!(
757 scope.count_permissions(),
758 2,
759 "Expected scope to contain 2 items"
760 );
761 }
762
763 #[test]
764 fn invalid_scope_deserializes_from_invalid_value() {
765 let json = json!(12345);
766 let result: Result<Scope, _> = serde_json::from_value(json);
767 assert!(
768 result.is_err(),
769 "Expected deserialization to fail for invalid scope"
770 );
771 }
772 }
773
774 mod merge {
775 use super::*;
776
777 #[test]
778 fn non_overlapping() {
779 let scope1 = Scope::parse("dataset:create");
780 let scope2 = Scope::parse("client:list");
781 let merged = scope1.merge(scope2);
782
783 assert!(merged.has_permission(Permission::Keyset(KeysetPermission::Create)));
784 assert!(merged.has_permission(Permission::Client(ClientPermission::List)));
785 assert_eq!(merged.count_permissions(), 2);
786 }
787
788 #[test]
789 fn overlapping() {
790 let scope1 = Scope::parse("dataset:create client:list");
791 let scope2 = Scope::parse("client:list data_key:generate");
792 let merged = scope1.merge(scope2);
793 assert!(merged.has_permission(Permission::Keyset(KeysetPermission::Create)));
794 assert!(merged.has_permission(Permission::Client(ClientPermission::List)));
795 assert!(merged.has_permission(Permission::DataKey(DataKeyPermission::Generate)));
796 assert_eq!(merged.count_permissions(), 3);
797 }
798 }
799
800 mod ensure_bitflag_representation_has_no_collisions {
801 use super::*;
802
803 mod scope_with_all_permissions {
804 use super::*;
805
806 #[test]
807 fn for_each_permission_has_permission_returns_true() {
808 let mut scope = Scope::with_no_permissions();
809 for permission in Permission::ALL {
810 scope = scope.merge(Scope::with_permission(*permission));
811 }
812
813 for permission in Permission::ALL {
814 assert!(scope.has_permission(*permission))
815 }
816 }
817 }
818
819 mod scope_with_all_but_one_permssion {
820 use super::*;
821
822 #[test]
823 fn has_permission_returns_true_for_all_except_one_permission() {
824 for without_permission in Permission::ALL {
825 let permissions: Vec<_> = Permission::ALL
826 .iter()
827 .filter(|p| *p != without_permission)
828 .copied()
829 .collect();
830 let scope = Scope::with_permissions(PermissionFlags::from_iter(
831 permissions.into_iter(),
832 ));
833
834 for permission in Permission::ALL {
835 if permission != without_permission {
836 assert!(scope.has_permission(*permission))
837 } else {
838 assert!(!scope.has_permission(*permission))
839 }
840 }
841 }
842 }
843 }
844 }
845}