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