alibi_plugins/oauth_provider/
post_login.rs1use alibi_core::{AuthResult, SessionView, UserView};
2use async_trait::async_trait;
3use std::{collections::HashMap, sync::Arc};
4
5pub struct OAuthInteractionContext<'a> {
8 pub headers: &'a HashMap<String, String>,
9 pub user: &'a UserView,
10 pub session: &'a SessionView,
11 pub scopes: &'a [String],
12}
13
14pub struct OAuthPostLoginContext<'a> {
17 pub headers: &'a HashMap<String, String>,
18 pub user: &'a UserView,
19 pub session: &'a SessionView,
20 pub scopes: &'a [String],
21 pub is_continuation: bool,
26}
27
28#[async_trait]
29pub trait OAuthPostLoginPolicy: Send + Sync + std::fmt::Debug {
30 async fn should_redirect(&self, input: OAuthPostLoginContext<'_>) -> AuthResult<bool>;
31}
32
33pub struct OAuthConsentReferenceContext<'a> {
36 pub user: &'a UserView,
37 pub session: &'a SessionView,
38 pub scopes: &'a [String],
39}
40
41#[async_trait]
42pub trait OAuthConsentReference: Send + Sync + std::fmt::Debug {
43 async fn consent_reference_id(
44 &self,
45 input: OAuthConsentReferenceContext<'_>,
46 ) -> AuthResult<Option<String>>;
47}
48
49#[derive(Debug, Clone)]
51pub struct OAuthPostLoginConfig {
52 pub page: String,
53 pub should_redirect: Arc<dyn OAuthPostLoginPolicy>,
54 pub consent_reference_id: Option<Arc<dyn OAuthConsentReference>>,
59}
60
61impl super::OAuthProviderPlugin {
62 pub(super) async fn consent_reference_id(
63 &self,
64 user: &UserView,
65 session: &SessionView,
66 scopes: &[String],
67 ) -> AuthResult<Option<String>> {
68 let Some(reference) = self
69 .config
70 .post_login
71 .as_ref()
72 .and_then(|config| config.consent_reference_id.as_ref())
73 else {
74 return Ok(None);
75 };
76 reference
77 .consent_reference_id(OAuthConsentReferenceContext {
78 user,
79 session,
80 scopes,
81 })
82 .await
83 .map(|reference| reference.filter(|reference| !reference.is_empty()))
84 .map_err(|error| {
85 if alibi_core::endpoint::is_endpoint_api_error(&error) {
86 error
87 } else {
88 alibi_core::AuthError::CallbackFailure(Box::new(error))
89 }
90 })
91 }
92}
93pub(super) fn consent_matches_reference(
96 metadata: &serde_json::Value,
97 reference: Option<&str>,
98) -> bool {
99 let stored = metadata
100 .get("referenceId")
101 .and_then(serde_json::Value::as_str)
102 .filter(|stored| !stored.is_empty());
103 stored == reference
104}