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