1use crate::interaction_code::generate_code;
2use crate::server::deferred::{DeferRequirement, PendingInput};
3use crate::types::AAuthProtocolError;
4
5use super::access::{AccessTokenContext, AccessTokenPolicy};
6use super::decision::{AuthGrant, PersonTokenDecision, ResourceConsentDecision, TokenPolicyDecision};
7use super::error::PolicyError;
8use super::person::{PersonTokenContext, PersonTokenPolicy};
9use super::resource::{ResourceAccessContext, ResourceConsentPolicy};
10
11#[derive(Debug, Clone, Default)]
12pub struct AlwaysGrantPersonPolicy {
13 pub sub: String,
14}
15
16impl AlwaysGrantPersonPolicy {
17 pub fn new(sub: impl Into<String>) -> Self {
18 Self { sub: sub.into() }
19 }
20}
21
22#[async_trait::async_trait]
23impl PersonTokenPolicy for AlwaysGrantPersonPolicy {
24 async fn evaluate(&self, ctx: &PersonTokenContext) -> Result<PersonTokenDecision, PolicyError> {
25 if ctx.audience_is_person_server() {
26 Ok(PersonTokenDecision::Grant(AuthGrant {
27 sub: self.sub.clone(),
28 scope: ctx.resource_claims.scope.clone(),
29 }))
30 } else {
31 Ok(PersonTokenDecision::Federate)
32 }
33 }
34
35 async fn resume(
36 &self,
37 ctx: &PersonTokenContext,
38 input: PendingInput,
39 ) -> Result<PersonTokenDecision, PolicyError> {
40 match input {
41 PendingInput::InteractionCompleted | PendingInput::ClarificationResponse(_) => {
42 self.evaluate(ctx).await
43 }
44 PendingInput::Cancelled => Ok(PersonTokenDecision::Deny(AAuthProtocolError {
45 error: "access_denied".into(),
46 error_description: Some("Request cancelled".into()),
47 error_uri: None,
48 })),
49 PendingInput::ClaimsSubmission(_) => Err(PolicyError::Message(
50 "claims submission not expected".into(),
51 )),
52 }
53 }
54}
55
56#[derive(Debug, Clone)]
57pub struct FixedSubPersonPolicy {
58 pub sub: String,
59}
60
61#[async_trait::async_trait]
62impl PersonTokenPolicy for FixedSubPersonPolicy {
63 async fn evaluate(&self, ctx: &PersonTokenContext) -> Result<PersonTokenDecision, PolicyError> {
64 AlwaysGrantPersonPolicy::new(&self.sub)
65 .evaluate(ctx)
66 .await
67 }
68
69 async fn resume(
70 &self,
71 ctx: &PersonTokenContext,
72 input: PendingInput,
73 ) -> Result<PersonTokenDecision, PolicyError> {
74 AlwaysGrantPersonPolicy::new(&self.sub)
75 .resume(ctx, input)
76 .await
77 }
78}
79
80#[derive(Debug, Clone, Default)]
81pub struct AlwaysGrantAccessPolicy {
82 pub sub: String,
83}
84
85impl AlwaysGrantAccessPolicy {
86 pub fn new(sub: impl Into<String>) -> Self {
87 Self { sub: sub.into() }
88 }
89}
90
91#[async_trait::async_trait]
92impl AccessTokenPolicy for AlwaysGrantAccessPolicy {
93 async fn evaluate(&self, ctx: &AccessTokenContext) -> Result<TokenPolicyDecision, PolicyError> {
94 Ok(TokenPolicyDecision::Grant(AuthGrant {
95 sub: self.sub.clone(),
96 scope: ctx.resource_claims.scope.clone(),
97 }))
98 }
99
100 async fn resume(
101 &self,
102 ctx: &AccessTokenContext,
103 input: PendingInput,
104 ) -> Result<TokenPolicyDecision, PolicyError> {
105 match input {
106 PendingInput::InteractionCompleted | PendingInput::ClarificationResponse(_) => {
107 self.evaluate(ctx).await
108 }
109 PendingInput::Cancelled => Ok(TokenPolicyDecision::Deny(AAuthProtocolError {
110 error: "access_denied".into(),
111 error_description: Some("Request cancelled".into()),
112 error_uri: None,
113 })),
114 PendingInput::ClaimsSubmission(_) => self.evaluate(ctx).await,
115 }
116 }
117}
118
119#[derive(Debug, Clone, Default)]
120pub struct AlwaysGrantResourcePolicy;
121
122#[async_trait::async_trait]
123impl ResourceConsentPolicy for AlwaysGrantResourcePolicy {
124 async fn evaluate(
125 &self,
126 _ctx: &ResourceAccessContext,
127 ) -> Result<ResourceConsentDecision, PolicyError> {
128 Ok(ResourceConsentDecision::GrantOpaque)
129 }
130
131 async fn resume(
132 &self,
133 _ctx: &ResourceAccessContext,
134 input: PendingInput,
135 ) -> Result<ResourceConsentDecision, PolicyError> {
136 match input {
137 PendingInput::InteractionCompleted => Ok(ResourceConsentDecision::GrantOpaque),
138 PendingInput::Cancelled => Ok(ResourceConsentDecision::Deny(AAuthProtocolError {
139 error: "access_denied".into(),
140 error_description: Some("Request cancelled".into()),
141 error_uri: None,
142 })),
143 _ => Ok(ResourceConsentDecision::GrantOpaque),
144 }
145 }
146}
147
148#[derive(Debug, Clone)]
149pub struct DeferInteractionResourcePolicy {
150 pub interaction_url: String,
151}
152
153#[async_trait::async_trait]
154impl ResourceConsentPolicy for DeferInteractionResourcePolicy {
155 async fn evaluate(
156 &self,
157 _ctx: &ResourceAccessContext,
158 ) -> Result<ResourceConsentDecision, PolicyError> {
159 Ok(ResourceConsentDecision::Defer(DeferRequirement::Interaction {
160 url: self.interaction_url.clone(),
161 code: generate_code(),
162 }))
163 }
164
165 async fn resume(
166 &self,
167 _ctx: &ResourceAccessContext,
168 input: PendingInput,
169 ) -> Result<ResourceConsentDecision, PolicyError> {
170 match input {
171 PendingInput::InteractionCompleted => Ok(ResourceConsentDecision::GrantOpaque),
172 PendingInput::Cancelled => Ok(ResourceConsentDecision::Deny(AAuthProtocolError {
173 error: "access_denied".into(),
174 error_description: Some("Request cancelled".into()),
175 error_uri: None,
176 })),
177 _ => Ok(ResourceConsentDecision::GrantOpaque),
178 }
179 }
180}
181
182#[derive(Debug, Clone)]
183pub struct ClarificationThenGrantPersonPolicy {
184 pub sub: String,
185 pub question: String,
186}
187
188#[async_trait::async_trait]
189impl PersonTokenPolicy for ClarificationThenGrantPersonPolicy {
190 async fn evaluate(&self, _ctx: &PersonTokenContext) -> Result<PersonTokenDecision, PolicyError> {
191 Ok(PersonTokenDecision::Defer(DeferRequirement::Clarification {
192 question: self.question.clone(),
193 timeout: None,
194 }))
195 }
196
197 async fn resume(
198 &self,
199 ctx: &PersonTokenContext,
200 input: PendingInput,
201 ) -> Result<PersonTokenDecision, PolicyError> {
202 match input {
203 PendingInput::ClarificationResponse(_) | PendingInput::InteractionCompleted => {
204 if ctx.audience_is_person_server() {
205 Ok(PersonTokenDecision::Grant(AuthGrant {
206 sub: self.sub.clone(),
207 scope: ctx.resource_claims.scope.clone(),
208 }))
209 } else {
210 Ok(PersonTokenDecision::Federate)
211 }
212 }
213 PendingInput::Cancelled => Ok(PersonTokenDecision::Deny(AAuthProtocolError {
214 error: "access_denied".into(),
215 error_description: Some("Request cancelled".into()),
216 error_uri: None,
217 })),
218 PendingInput::ClaimsSubmission(_) => Err(PolicyError::Message(
219 "claims submission not expected".into(),
220 )),
221 }
222 }
223}
224
225#[derive(Debug, Clone)]
226pub struct DeferInteractionPersonPolicy<P> {
227 pub inner: P,
228 pub interaction_url: String,
229}
230
231#[async_trait::async_trait]
232impl<P> PersonTokenPolicy for DeferInteractionPersonPolicy<P>
233where
234 P: PersonTokenPolicy + Send + Sync + Clone,
235{
236 async fn evaluate(&self, _ctx: &PersonTokenContext) -> Result<PersonTokenDecision, PolicyError> {
237 Ok(PersonTokenDecision::Defer(DeferRequirement::Interaction {
238 url: self.interaction_url.clone(),
239 code: generate_code(),
240 }))
241 }
242
243 async fn resume(
244 &self,
245 ctx: &PersonTokenContext,
246 input: PendingInput,
247 ) -> Result<PersonTokenDecision, PolicyError> {
248 self.inner.resume(ctx, input).await
249 }
250}
251
252#[derive(Debug, Clone)]
253pub struct ClarificationThenGrantAccessPolicy {
254 pub sub: String,
255 pub question: String,
256}
257
258#[async_trait::async_trait]
259impl AccessTokenPolicy for ClarificationThenGrantAccessPolicy {
260 async fn evaluate(&self, _ctx: &AccessTokenContext) -> Result<TokenPolicyDecision, PolicyError> {
261 Ok(TokenPolicyDecision::Defer(DeferRequirement::Clarification {
262 question: self.question.clone(),
263 timeout: None,
264 }))
265 }
266
267 async fn resume(
268 &self,
269 ctx: &AccessTokenContext,
270 input: PendingInput,
271 ) -> Result<TokenPolicyDecision, PolicyError> {
272 match input {
273 PendingInput::ClarificationResponse(_) | PendingInput::InteractionCompleted => {
274 Ok(TokenPolicyDecision::Grant(AuthGrant {
275 sub: self.sub.clone(),
276 scope: ctx.resource_claims.scope.clone(),
277 }))
278 }
279 PendingInput::Cancelled => Ok(TokenPolicyDecision::Deny(AAuthProtocolError {
280 error: "access_denied".into(),
281 error_description: Some("Request cancelled".into()),
282 error_uri: None,
283 })),
284 PendingInput::ClaimsSubmission(_) => Err(PolicyError::Message(
285 "claims submission not expected".into(),
286 )),
287 }
288 }
289}
290
291#[derive(Debug, Clone)]
292pub struct DeferInteractionAccessPolicy<P> {
293 pub inner: P,
294 pub interaction_url: String,
295}
296
297#[async_trait::async_trait]
298impl<P> AccessTokenPolicy for DeferInteractionAccessPolicy<P>
299where
300 P: AccessTokenPolicy + Send + Sync + Clone,
301{
302 async fn evaluate(&self, _ctx: &AccessTokenContext) -> Result<TokenPolicyDecision, PolicyError> {
303 Ok(TokenPolicyDecision::Defer(DeferRequirement::Interaction {
304 url: self.interaction_url.clone(),
305 code: generate_code(),
306 }))
307 }
308
309 async fn resume(
310 &self,
311 ctx: &AccessTokenContext,
312 input: PendingInput,
313 ) -> Result<TokenPolicyDecision, PolicyError> {
314 self.inner.resume(ctx, input).await
315 }
316}
317
318#[derive(Debug, Clone)]
319pub struct DeferClaimsAccessPolicy {
320 pub sub: String,
321 pub required_claims: Vec<String>,
322}
323
324#[async_trait::async_trait]
325impl AccessTokenPolicy for DeferClaimsAccessPolicy {
326 async fn evaluate(&self, _ctx: &AccessTokenContext) -> Result<TokenPolicyDecision, PolicyError> {
327 Ok(TokenPolicyDecision::Defer(DeferRequirement::Claims {
328 required_claims: self.required_claims.clone(),
329 }))
330 }
331
332 async fn resume(
333 &self,
334 ctx: &AccessTokenContext,
335 input: PendingInput,
336 ) -> Result<TokenPolicyDecision, PolicyError> {
337 match input {
338 PendingInput::ClaimsSubmission(_) | PendingInput::InteractionCompleted => {
339 Ok(TokenPolicyDecision::Grant(AuthGrant {
340 sub: self.sub.clone(),
341 scope: ctx.resource_claims.scope.clone(),
342 }))
343 }
344 PendingInput::Cancelled => Ok(TokenPolicyDecision::Deny(AAuthProtocolError {
345 error: "access_denied".into(),
346 error_description: Some("Request cancelled".into()),
347 error_uri: None,
348 })),
349 PendingInput::ClarificationResponse(_) => Err(PolicyError::Message(
350 "clarification not expected".into(),
351 )),
352 }
353 }
354}
355
356#[derive(Debug, Clone, Default)]
357pub struct DeferApprovalAccessPolicy {
358 pub sub: String,
359}
360
361#[async_trait::async_trait]
362impl AccessTokenPolicy for DeferApprovalAccessPolicy {
363 async fn evaluate(&self, _ctx: &AccessTokenContext) -> Result<TokenPolicyDecision, PolicyError> {
364 Ok(TokenPolicyDecision::Defer(DeferRequirement::Approval))
365 }
366
367 async fn resume(
368 &self,
369 ctx: &AccessTokenContext,
370 input: PendingInput,
371 ) -> Result<TokenPolicyDecision, PolicyError> {
372 match input {
373 PendingInput::InteractionCompleted => Ok(TokenPolicyDecision::Grant(AuthGrant {
374 sub: self.sub.clone(),
375 scope: ctx.resource_claims.scope.clone(),
376 })),
377 PendingInput::Cancelled => Ok(TokenPolicyDecision::Deny(AAuthProtocolError {
378 error: "access_denied".into(),
379 error_description: Some("Request cancelled".into()),
380 error_uri: None,
381 })),
382 _ => Ok(TokenPolicyDecision::Grant(AuthGrant {
383 sub: self.sub.clone(),
384 scope: ctx.resource_claims.scope.clone(),
385 })),
386 }
387 }
388}