1use super::{
15 AccessAction, AccessDecisionError, AccessResource, AdmittedLysPass, DeliberateDecision,
16 GrantReceipt, HotAction, LysDeliberateConsumer, LysPassConsumer, SubjectBinding,
17 admit_lys_pass, decide_deliberate, decide_message,
18};
19use crate::link::LinkAction;
20use std::sync::Arc;
21
22impl SubjectBinding {
23 pub fn link(
28 network_id: String,
29 link_id: String,
30 subject: String,
31 ) -> Result<Self, super::SubjectBindingError> {
32 let mut binding = Self::new(network_id, link_id, subject)?;
33 binding.resource.kind = super::ResourceKind::Link;
34 Ok(binding)
35 }
36}
37
38#[derive(Debug)]
40pub struct LysAdmissionRefusal {
41 pub reason: String,
43}
44
45impl std::fmt::Display for LysAdmissionRefusal {
46 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
47 write!(formatter, "lys pass admission refused: {}", self.reason)
48 }
49}
50
51impl std::error::Error for LysAdmissionRefusal {}
52
53pub trait LysAdmitter: Send + Sync + std::fmt::Debug {
55 fn admit(&self, pass: &[u8], now: u64) -> Result<Box<dyn LysSession>, LysAdmissionRefusal>;
61}
62
63pub trait LysSession: Send + Sync + std::fmt::Debug {
65 fn holder(&self) -> &str;
67
68 fn holder_kind(&self) -> Option<&str> {
72 None
73 }
74
75 fn issued_at(&self) -> Option<u64> {
78 None
79 }
80
81 fn decide(
86 &self,
87 subject: &SubjectBinding,
88 action: HotAction,
89 now: u64,
90 ) -> Result<GrantReceipt, AccessDecisionError>;
91
92 fn decide_link(
98 &self,
99 subject: &SubjectBinding,
100 action: LinkAction,
101 now: u64,
102 ) -> Result<GrantReceipt, AccessDecisionError>;
103
104 fn open_link(
111 &self,
112 link: &AccessResource,
113 end: LinkAction,
114 now: u64,
115 ) -> Result<DeliberateDecision, AccessDecisionError>;
116
117 fn decide_live(
126 &self,
127 resource: &AccessResource,
128 action: AccessAction,
129 now: u64,
130 ) -> Result<DeliberateDecision, AccessDecisionError>;
131}
132
133#[derive(Debug)]
135pub struct ConsumerAdmitter<C> {
136 consumer: Arc<C>,
137}
138
139impl<C> ConsumerAdmitter<C> {
140 #[must_use]
142 pub const fn new(consumer: Arc<C>) -> Self {
143 Self { consumer }
144 }
145}
146
147struct ConsumerSession<C: LysPassConsumer> {
148 consumer: Arc<C>,
149 pass: AdmittedLysPass<C::Pass>,
150 holder: String,
151 holder_kind: Option<String>,
154}
155
156impl<C: LysPassConsumer> std::fmt::Debug for ConsumerSession<C> {
157 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
158 formatter
159 .debug_struct("ConsumerSession")
160 .field("holder", &self.holder)
161 .finish_non_exhaustive()
162 }
163}
164
165impl<C> LysAdmitter for ConsumerAdmitter<C>
166where
167 C: LysDeliberateConsumer + Send + Sync + std::fmt::Debug + 'static,
168 C::Pass: Send + Sync + 'static,
169 C::Holder: AsRef<str>,
170{
171 fn admit(&self, pass: &[u8], now: u64) -> Result<Box<dyn LysSession>, LysAdmissionRefusal> {
172 let admitted = admit_lys_pass(self.consumer.as_ref(), pass, now).map_err(|error| {
173 LysAdmissionRefusal {
174 reason: error.to_string(),
175 }
176 })?;
177 let holder = self
178 .consumer
179 .verified_holder(&admitted.pass)
180 .as_ref()
181 .to_owned();
182 let holder_kind = self
183 .consumer
184 .verified_holder_kind(&admitted.pass)
185 .map(str::to_owned);
186 Ok(Box::new(ConsumerSession {
187 consumer: Arc::clone(&self.consumer),
188 pass: admitted,
189 holder,
190 holder_kind,
191 }))
192 }
193}
194
195impl<C> LysSession for ConsumerSession<C>
196where
197 C: LysDeliberateConsumer + Send + Sync + 'static,
198 C::Pass: Send + Sync + 'static,
199{
200 fn holder(&self) -> &str {
201 &self.holder
202 }
203
204 fn holder_kind(&self) -> Option<&str> {
205 self.holder_kind.as_deref()
206 }
207
208 fn issued_at(&self) -> Option<u64> {
209 self.consumer.verified_issued_at(&self.pass.pass)
210 }
211
212 fn decide(
213 &self,
214 subject: &SubjectBinding,
215 action: HotAction,
216 now: u64,
217 ) -> Result<GrantReceipt, AccessDecisionError> {
218 decide_message(self.consumer.as_ref(), &self.pass, subject, action, now)
219 }
220
221 fn decide_link(
222 &self,
223 subject: &SubjectBinding,
224 action: LinkAction,
225 now: u64,
226 ) -> Result<GrantReceipt, AccessDecisionError> {
227 self.consumer
228 .decide_link(&self.pass.pass, subject, action, now)
229 }
230
231 fn open_link(
232 &self,
233 link: &AccessResource,
234 end: LinkAction,
235 now: u64,
236 ) -> Result<DeliberateDecision, AccessDecisionError> {
237 self.decide_live(link, end.access_action(), now)
238 }
239
240 fn decide_live(
241 &self,
242 resource: &AccessResource,
243 action: AccessAction,
244 now: u64,
245 ) -> Result<DeliberateDecision, AccessDecisionError> {
246 decide_deliberate(self.consumer.as_ref(), &self.pass, resource, action, now)
247 }
248}