surrealdb/iam/entities/resources/
actor.rs

1use revision::revisioned;
2use std::collections::{HashMap, HashSet};
3use std::ops::Deref;
4use std::str::FromStr;
5
6use cedar_policy::{Entity, EntityId, EntityTypeName, EntityUid, RestrictedExpression};
7use serde::{Deserialize, Serialize};
8
9use super::{Level, Resource, ResourceKind};
10use crate::iam::Role;
11use crate::sql::statements::{DefineTokenStatement, DefineUserStatement};
12
13//
14// User
15//
16#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Hash, Serialize, Deserialize)]
17#[revisioned(revision = 1)]
18pub struct Actor {
19	res: Resource,
20	roles: Vec<Role>,
21}
22
23impl Default for Actor {
24	fn default() -> Self {
25		Self {
26			res: ResourceKind::Actor.on_level(Level::No),
27			roles: Vec::new(),
28		}
29	}
30}
31
32impl std::fmt::Display for Actor {
33	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
34		if self.res.level() == &Level::No {
35			return write!(f, "Actor::Anonymous");
36		}
37
38		write!(
39			f,
40			"{}{}::{}({})",
41			self.res.level(),
42			self.res.kind(),
43			self.res.id(),
44			self.roles.iter().map(|r| format!("{}", r)).collect::<Vec<String>>().join(", ")
45		)
46	}
47}
48
49impl Actor {
50	pub fn new(id: String, roles: Vec<Role>, level: Level) -> Self {
51		Self {
52			res: Resource::new(id, super::ResourceKind::Actor, level),
53			roles,
54		}
55	}
56
57	/// Checks if the actor has the given role.
58	pub fn has_role(&self, role: &Role) -> bool {
59		self.roles.contains(role)
60	}
61
62	// Cedar policy helpers
63	pub fn cedar_attrs(&self) -> HashMap<String, RestrictedExpression> {
64		[
65			("type", self.kind().into()),
66			("level", self.level().into()),
67			("roles", RestrictedExpression::new_set(self.roles.iter().map(|r| r.into()))),
68		]
69		.into_iter()
70		.map(|(x, v)| (x.into(), v))
71		.collect()
72	}
73
74	pub fn cedar_parents(&self) -> HashSet<EntityUid> {
75		let mut parents = HashSet::with_capacity(1);
76		parents.insert(self.res.level().into());
77		parents
78	}
79
80	pub fn cedar_entities(&self) -> Vec<Entity> {
81		let mut entities = Vec::new();
82
83		entities.push(self.into());
84
85		for role in self.roles.iter() {
86			entities.push(role.into());
87		}
88
89		for level in self.res.level().cedar_entities() {
90			entities.push(level);
91		}
92
93		entities
94	}
95}
96
97impl Deref for Actor {
98	type Target = Resource;
99	fn deref(&self) -> &Self::Target {
100		&self.res
101	}
102}
103
104impl std::convert::From<&Actor> for EntityUid {
105	fn from(actor: &Actor) -> Self {
106		EntityUid::from_type_name_and_id(
107			EntityTypeName::from_str("Actor").unwrap(),
108			EntityId::from_str(actor.id()).unwrap(),
109		)
110	}
111}
112
113impl std::convert::From<&Actor> for Entity {
114	fn from(actor: &Actor) -> Self {
115		Entity::new(actor.into(), actor.cedar_attrs(), actor.cedar_parents())
116	}
117}
118
119impl std::convert::From<(&DefineUserStatement, Level)> for Actor {
120	fn from(val: (&DefineUserStatement, Level)) -> Self {
121		Self::new(val.0.name.to_string(), val.0.roles.iter().map(Role::from).collect(), val.1)
122	}
123}
124
125impl std::convert::From<(&DefineTokenStatement, Level)> for Actor {
126	fn from(val: (&DefineTokenStatement, Level)) -> Self {
127		Self::new(val.0.name.to_string(), Vec::default(), val.1)
128	}
129}