alibi_plugins/helpers/
mod.rs1mod api_key_authorization;
3mod credentials;
4mod sessions;
5
6use alibi_core::{AuthContext, AuthError, CreateUser};
7pub use api_key_authorization::{get_owned_api_key, require_org_api_key_permission};
8pub use credentials::{get_credential_account, get_credential_password_hash, user_has_password};
9pub use sessions::{
10 admin_banned_user_message, admin_plugin_enabled, delete_session_cookie_headers,
11 expires_in_to_at, get_cookie, issue_user_session, issue_user_session_record,
12 issue_user_session_with_fields, issue_user_session_with_fields_record,
13 issue_user_session_with_overrides, issue_user_session_with_overrides_record, response_session,
14};
15pub(crate) use sessions::{
16 completed_response_session, create_user_session_record, issue_selected_user_session_record,
17 ordinary_session, record_completed_session, record_completed_session_record,
18 record_completed_session_user_view, response_has_session_cookie,
19};
20
21pub(crate) fn auth_base_url(config: &alibi_core::AuthConfig) -> String {
23 let origin = config.base_url.trim_end_matches('/');
24 let path = config.base_path.trim_matches('/');
25 if path.is_empty() {
26 origin.to_owned()
27 } else {
28 format!("{origin}/{path}")
29 }
30}
31
32pub(crate) fn callback_failure(error: AuthError) -> AuthError {
35 if matches!(
36 error,
37 AuthError::Api { .. } | AuthError::Upstream { .. } | AuthError::CallbackFailure(_)
38 ) {
39 error
40 } else {
41 AuthError::CallbackFailure(Box::new(error))
42 }
43}
44
45pub(crate) fn spawn_in_request_context(work: impl Future<Output = ()> + Send + 'static) {
48 let endpoint = alibi_core::endpoint::current_endpoint_call_context();
49 let hook = alibi_core::hooks::current_request_hook_context();
50 _ = tokio::spawn(async move {
51 let work = alibi_core::hooks::with_optional_request_hook_context(hook, work);
52 if let Some(endpoint) = endpoint {
53 alibi_core::endpoint::with_endpoint_call_context(endpoint, work).await;
54 } else {
55 work.await;
56 }
57 });
58}
59
60pub(crate) const fn unauthorized() -> AuthError {
62 AuthError::Upstream {
63 status: 401,
64 code: "UNAUTHORIZED",
65 message: "Unauthorized",
66 }
67}
68
69pub(crate) fn unauthorized_if_unauthenticated(error: AuthError) -> AuthError {
71 if matches!(error, AuthError::Unauthenticated) {
72 unauthorized()
73 } else {
74 error
75 }
76}
77
78pub(crate) fn unauthorized_if_session_missing(error: AuthError) -> AuthError {
81 if matches!(
82 error,
83 AuthError::Unauthenticated | AuthError::SessionNotFound | AuthError::UserNotFound
84 ) {
85 unauthorized()
86 } else {
87 error
88 }
89}
90
91pub struct IssuedSession<S: alibi_core::AuthSchema> {
93 pub user: S::User,
94 pub session: S::Session,
95}
96
97pub struct IssuedSessionRecord<S: alibi_core::AuthSchema> {
100 pub user: alibi_core::AdapterRecord<S::User>,
101 pub session: alibi_core::AdapterRecord<S::Session>,
102}
103impl<S: alibi_core::AuthSchema> IssuedSessionRecord<S> {
104 fn into_stored(self) -> IssuedSession<S> {
105 IssuedSession {
106 user: self.user.into_stored(),
107 session: self.session.into_stored(),
108 }
109 }
110}
111
112pub(crate) struct CompletedSession<S: alibi_core::AuthSchema> {
115 pub(crate) user: S::User,
116 pub(crate) session: S::Session,
117 pub(crate) user_view: Option<alibi_core::wire::UserView>,
118 user_record: Option<alibi_core::AdapterRecord<S::User>>,
119 session_record: Option<alibi_core::AdapterRecord<S::Session>>,
120}
121impl<S: alibi_core::AuthSchema> CompletedSession<S> {
122 pub(crate) fn callback_user(&self, ctx: &AuthContext<S>) -> alibi_core::UserView {
123 self.user_view.clone().unwrap_or_else(|| {
124 self.user_record.as_ref().map_or_else(
125 || ctx.trusted_user_view(&self.user),
126 |record| ctx.trusted_user_view(record),
127 )
128 })
129 }
130 pub(crate) fn callback_session(&self, ctx: &AuthContext<S>) -> alibi_core::SessionView {
131 self.session_record.as_ref().map_or_else(
132 || ctx.trusted_session_view(&self.session),
133 |record| ctx.trusted_session_view(record),
134 )
135 }
136}
137
138#[derive(Debug)]
141pub enum SessionIssueError {
142 Auth(AuthError),
143 Banned { message: String },
144}
145
146impl SessionIssueError {
147 #[must_use]
148 pub fn into_auth_error(self) -> AuthError {
149 match self {
150 Self::Auth(error) => error,
151 Self::Banned { message } => AuthError::banned_user(message),
152 }
153 }
154
155 #[must_use]
156 pub const fn banned_message(&self) -> Option<&str> {
157 match self {
158 Self::Banned { message } => Some(message.as_str()),
159 Self::Auth(_) => None,
160 }
161 }
162}
163
164impl From<AuthError> for SessionIssueError {
165 fn from(value: AuthError) -> Self {
166 Self::Auth(value)
167 }
168}
169
170#[derive(Clone, Debug, Default)]
177pub struct SessionOverrides {
178 pub additional_fields: alibi_core::field_policy::FieldValues,
180 pub impersonated_by: Option<String>,
182 pub active_organization_id: Option<String>,
184 pub active_team_id: Option<String>,
186}
187
188impl<S: alibi_core::AuthSchema> std::fmt::Debug for IssuedSession<S> {
189 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
190 f.debug_struct("IssuedSession").finish_non_exhaustive()
191 }
192}
193
194pub fn apply_default_role(
197 ctx: &AuthContext<impl alibi_core::AuthSchema>,
198 create_user: &mut CreateUser,
199) {
200 if ctx.config.user_validation.is_some() || create_user.role.is_some() {
203 return;
204 }
205
206 if let Some(default_role) = ctx
207 .get_metadata("admin.default_role")
208 .and_then(|value| value.as_str())
209 {
210 create_user.role = Some(default_role.to_owned());
211 }
212}