cedar_policy_core/ast/
request.rs1use crate::ast::{BorrowedRestrictedExpr, EntityUID, ExprKind, RestrictedExpr};
18use crate::entities::{ContextJsonParser, JsonDeserializationError, NullContextSchema};
19use crate::extensions::Extensions;
20use serde::{Deserialize, Serialize};
21use smol_str::SmolStr;
22use std::sync::Arc;
23
24use super::{Expr, Literal, PartialValue, Value, Var};
25
26#[derive(Debug, Clone, Serialize, Deserialize)]
28pub struct Request {
29 pub(crate) principal: EntityUIDEntry,
32
33 pub(crate) action: EntityUIDEntry,
36
37 pub(crate) resource: EntityUIDEntry,
40
41 pub(crate) context: Option<Context>,
44}
45
46#[derive(Debug, Clone, Serialize, Deserialize)]
50pub enum EntityUIDEntry {
51 Concrete(Arc<EntityUID>),
53 Unknown,
55}
56
57impl EntityUIDEntry {
58 pub fn evaluate(&self, var: Var) -> PartialValue {
62 match self {
63 EntityUIDEntry::Concrete(euid) => Value::Lit(Literal::EntityUID(euid.clone())).into(),
64 EntityUIDEntry::Unknown => Expr::unknown(var.to_string()).into(),
65 }
66 }
67
68 pub fn concrete(euid: EntityUID) -> Self {
70 Self::Concrete(Arc::new(euid))
71 }
72}
73
74impl Request {
75 pub fn new(
77 principal: EntityUID,
78 action: EntityUID,
79 resource: EntityUID,
80 context: Context,
81 ) -> Self {
82 Self {
83 principal: EntityUIDEntry::concrete(principal),
84 action: EntityUIDEntry::concrete(action),
85 resource: EntityUIDEntry::concrete(resource),
86 context: Some(context),
87 }
88 }
89
90 pub fn new_with_unknowns(
92 principal: EntityUIDEntry,
93 action: EntityUIDEntry,
94 resource: EntityUIDEntry,
95 context: Option<Context>,
96 ) -> Self {
97 Self {
98 principal,
99 action,
100 resource,
101 context,
102 }
103 }
104
105 pub fn principal(&self) -> &EntityUIDEntry {
107 &self.principal
108 }
109
110 pub fn action(&self) -> &EntityUIDEntry {
112 &self.action
113 }
114
115 pub fn resource(&self) -> &EntityUIDEntry {
117 &self.resource
118 }
119
120 pub fn context(&self) -> Option<&Context> {
123 self.context.as_ref()
124 }
125}
126
127impl std::fmt::Display for Request {
128 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
129 let display_euid = |maybe_euid: &EntityUIDEntry| match maybe_euid {
130 EntityUIDEntry::Concrete(euid) => format!("{euid}"),
131 EntityUIDEntry::Unknown => "unknown".to_string(),
132 };
133 write!(
134 f,
135 "request with principal {}, action {}, resource {}, and context {}",
136 display_euid(&self.principal),
137 display_euid(&self.action),
138 display_euid(&self.resource),
139 match &self.context {
140 Some(x) => format!("{x}"),
141 None => "unknown".to_string(),
142 }
143 )
144 }
145}
146
147#[derive(Debug, Clone, Serialize, Deserialize)]
149pub struct Context {
150 #[serde(flatten)]
152 context: RestrictedExpr,
153}
154
155impl Context {
156 pub fn empty() -> Self {
158 Self::from_pairs([])
159 }
160
161 pub fn from_expr(expr: RestrictedExpr) -> Self {
163 debug_assert!(matches!(expr.expr_kind(), ExprKind::Record { .. }));
164 Self { context: expr }
165 }
166
167 pub fn from_pairs(pairs: impl IntoIterator<Item = (SmolStr, RestrictedExpr)>) -> Self {
170 Self {
171 context: RestrictedExpr::record(pairs),
172 }
173 }
174
175 pub fn from_json_str(json: &str) -> Result<Self, JsonDeserializationError> {
182 ContextJsonParser::new(None::<&NullContextSchema>, Extensions::all_available())
183 .from_json_str(json)
184 }
185
186 pub fn from_json_value(json: serde_json::Value) -> Result<Self, JsonDeserializationError> {
193 ContextJsonParser::new(None::<&NullContextSchema>, Extensions::all_available())
194 .from_json_value(json)
195 }
196
197 pub fn from_json_file(json: impl std::io::Read) -> Result<Self, JsonDeserializationError> {
204 ContextJsonParser::new(None::<&NullContextSchema>, Extensions::all_available())
205 .from_json_file(json)
206 }
207
208 pub fn iter(&self) -> impl Iterator<Item = (&str, BorrowedRestrictedExpr<'_>)> {
210 match self.context.as_ref().expr_kind() {
211 ExprKind::Record { pairs } => pairs
212 .iter()
213 .map(|(k, v)| (k.as_str(), BorrowedRestrictedExpr::new_unchecked(v))), e => panic!("internal invariant violation: expected Expr::Record, got {e:?}"),
215 }
216 }
217}
218
219impl AsRef<RestrictedExpr> for Context {
220 fn as_ref(&self) -> &RestrictedExpr {
221 &self.context
222 }
223}
224
225impl std::default::Default for Context {
226 fn default() -> Context {
227 Context::empty()
228 }
229}
230
231impl std::fmt::Display for Context {
232 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
233 write!(f, "{}", self.context)
234 }
235}