1#![cfg_attr(
4 test,
5 allow(
6 unused_results,
7 unreachable_pub,
8 reason = "test code intentionally discards setup return values and exposes helpers broadly"
9 )
10)]
11
12#[cfg(all(feature = "native-tls", feature = "rustls"))]
13compile_error!(
14 "features `native-tls` and `rustls` are mutually exclusive. \
15 Enable exactly one of them: \
16 for `native-tls` (default), remove the `rustls` feature; \
17 for `rustls`, set `default-features = false, features = [\"rustls\"]`."
18);
19
20#[cfg(not(any(feature = "native-tls", feature = "rustls")))]
21compile_error!(
22 "one of the TLS backends must be enabled: \
23 enable either the `native-tls` (default) or `rustls` feature."
24);
25
26macro_rules! route_openapi_metadata {
29 ($schema:ident) => {
30 fn static_openapi_metadata(&self) -> alibi_core::PluginOpenApiMetadata {
31 crate::metadata::plugin_metadata(
32 <Self as alibi_core::AuthPlugin<$schema>>::name(self),
33 &<Self as alibi_core::AuthPlugin<$schema>>::routes(self),
34 )
35 }
36
37 fn openapi_metadata(
38 &self,
39 ctx: &alibi_core::AuthInitContext<$schema>,
40 ) -> alibi_core::PluginOpenApiMetadata {
41 crate::metadata::instance_plugin_metadata(
42 <Self as alibi_core::AuthPlugin<$schema>>::name(self),
43 &<Self as alibi_core::AuthPlugin<$schema>>::routes(self),
44 ctx,
45 )
46 }
47 };
48}
49
50pub mod access;
51pub mod account_management;
52pub mod admin;
53pub mod anonymous;
54pub mod api_key;
55pub(crate) mod authentication_helpers;
56pub mod bearer;
57pub mod captcha;
58pub mod custom_session;
59pub mod device_authorization;
60pub mod email_otp;
61pub mod email_password;
62pub mod email_verification;
63mod endpoint;
64pub mod haveibeenpwned;
65pub mod helpers;
66pub mod jwt;
67pub mod last_login_method;
68pub mod magic_link;
69pub mod metadata;
70pub mod multi_session;
71pub mod oauth;
72pub mod oauth_popup;
73pub mod oauth_proxy;
74pub mod oauth_token_conversion;
75pub mod one_tap;
76pub mod one_time_token;
77pub mod open_api;
78pub mod organization;
79#[cfg(feature = "passkey")]
80pub mod passkey;
81pub mod password_management;
82mod passwordless_numeric;
83pub mod phone_number;
84pub mod session_management;
85pub mod siwe;
86pub(crate) mod token_crypto;
87pub mod two_factor;
88pub mod user_management;
89
90#[cfg(test)]
92pub(crate) mod test_helpers {
93 use alibi_core::config::AuthConfig;
94 use alibi_core::wire::{SessionView, UserView};
95 use alibi_core::{AuthContext, AuthRequest, CreateSession, CreateUser, HttpMethod};
96 use alibi_seaorm::store::__private_test_support::bundled_schema::BundledSchema;
97 use alibi_seaorm::{Database, SeaOrmStore};
98 use chrono::{Duration, Utc};
99 use std::collections::HashMap;
100 use std::sync::Arc;
101
102 pub type TestDatabase = dyn alibi_core::store::AuthStore<BundledSchema>;
103
104 pub fn create_test_config() -> AuthConfig {
105 AuthConfig::new("test-secret-key-at-least-32-chars-long")
106 }
107
108 pub async fn create_test_database() -> Arc<TestDatabase> {
109 let database = Database::connect("sqlite::memory:")
110 .await
111 .expect("sqlite test database should connect");
112 alibi_seaorm::store::__private_test_support::migrator::run_migrations(&database)
113 .await
114 .expect("sqlite test migrations should run");
115 Arc::new(SeaOrmStore::<BundledSchema>::new(
116 Arc::new(create_test_config()),
117 database,
118 ))
119 }
120
121 pub async fn create_test_context() -> AuthContext<BundledSchema> {
122 create_test_context_with_config(create_test_config()).await
123 }
124
125 pub fn create_test_context_blocking() -> AuthContext<BundledSchema> {
126 tokio::runtime::Builder::new_current_thread()
127 .enable_all()
128 .build()
129 .expect("test runtime should build")
130 .block_on(create_test_context())
131 }
132
133 pub async fn create_test_context_with_config(config: AuthConfig) -> AuthContext<BundledSchema> {
134 let config = Arc::new(config);
135 let database = create_test_database().await;
136 AuthContext::new(config, database)
137 }
138
139 pub async fn create_user(
140 ctx: &AuthContext<impl alibi_core::AuthSchema>,
141 create_user: CreateUser,
142 ) -> UserView {
143 let user = ctx.database.create_user(create_user).await.unwrap();
144 UserView::from(&user)
145 }
146
147 pub async fn create_session(
148 ctx: &AuthContext<impl alibi_core::AuthSchema>,
149 user_id: String,
150 expires_in: Duration,
151 ) -> SessionView {
152 let create_session = CreateSession {
153 additional_fields: alibi_core::field_policy::FieldValues::default(),
154 token: None,
155 active_team_id: None,
156 user_id,
157 expires_at: Utc::now() + expires_in,
158 ip_address: Some("127.0.0.1".to_owned()),
159 user_agent: Some("test-agent".to_owned()),
160 impersonated_by: None,
161 active_organization_id: None,
162 };
163 let session = ctx.database.create_session(create_session).await.unwrap();
164 SessionView::from(&session)
165 }
166
167 pub async fn create_user_and_session(
168 ctx: &AuthContext<impl alibi_core::AuthSchema>,
169 user_data: CreateUser,
170 session_expires_in: Duration,
171 ) -> (UserView, SessionView) {
172 let user = create_user(ctx, user_data).await;
173 let session = create_session(ctx, user.id.clone(), session_expires_in).await;
174 (user, session)
175 }
176
177 pub async fn create_test_context_with_user(
178 create_user: CreateUser,
179 session_expires_in: Duration,
180 ) -> (AuthContext<BundledSchema>, UserView, SessionView) {
181 let ctx = create_test_context().await;
182 let (user, session) = create_user_and_session(&ctx, create_user, session_expires_in).await;
183 (ctx, user, session)
184 }
185
186 pub fn create_auth_request(
187 method: HttpMethod,
188 path: &str,
189 token: Option<&str>,
190 body: Option<Vec<u8>>,
191 query: HashMap<String, String>,
192 ) -> AuthRequest {
193 let mut headers = HashMap::new();
194 if let Some(token) = token {
195 let config = create_test_config();
196 headers.insert(
197 "cookie".to_owned(),
198 format!(
199 "{}={}",
200 config.session.cookie_name,
201 alibi_core::utils::cookie_utils::sign_cookie_value(
202 token,
203 config.current_secret()
204 )
205 ),
206 );
207 }
208
209 AuthRequest::from_parts(method, path.to_owned(), headers, body, query)
210 }
211
212 pub fn create_auth_request_no_query(
213 method: HttpMethod,
214 path: &str,
215 token: Option<&str>,
216 body: Option<Vec<u8>>,
217 ) -> AuthRequest {
218 create_auth_request(method, path, token, body, HashMap::new())
219 }
220
221 pub fn create_auth_json_request_no_query(
222 method: HttpMethod,
223 path: &str,
224 token: Option<&str>,
225 body: Option<serde_json::Value>,
226 ) -> AuthRequest {
227 create_auth_json_request(method, path, token, body, HashMap::new())
228 }
229
230 pub fn create_auth_json_request(
231 method: HttpMethod,
232 path: &str,
233 token: Option<&str>,
234 body: Option<serde_json::Value>,
235 query: HashMap<String, String>,
236 ) -> AuthRequest {
237 let mut req = create_auth_request(
238 method,
239 path,
240 token,
241 body.map(|b| serde_json::to_vec(&b).unwrap()),
242 query,
243 );
244 req.headers
245 .insert("content-type".to_owned(), "application/json".to_owned());
246 req
247 }
248}
249pub use account_management::AccountManagementPlugin;
252pub use admin::{
253 AdminBannedUserMessage, AdminBannedUserMessageHandler, AdminConfig, AdminPlugin,
254 RolePermissions,
255};
256pub use alibi_core::PasswordHasher;
257pub use anonymous::{
258 AnonymousConfig, AnonymousIdentity, AnonymousLink, AnonymousPlugin, LinkAnonymousAccount,
259};
260pub use api_key::{
261 ApiKeyCallbackContext, ApiKeyConfig, ApiKeyDefaultPermissions, ApiKeyErrorMessage,
262 ApiKeyGenerationOptions, ApiKeyGenerator, ApiKeyGetter, ApiKeyPermissions, ApiKeyPlugin,
263 ApiKeyValidator, DeleteExpiredApiKeysResponse,
264};
265pub use bearer::{BearerConfig, BearerPlugin};
266pub use captcha::{CaptchaConfig, CaptchaPlugin, CaptchaProvider};
267pub use custom_session::{CustomSessionPlugin, SessionTransform};
268pub use device_authorization::DeviceAuthorizationPlugin;
269pub use email_otp::{EmailOtpConfig, EmailOtpPlugin, SendEmailOtp};
270pub use email_password::{EmailPasswordConfig, EmailPasswordPlugin};
271pub use email_verification::{
272 EmailVerificationConfig, EmailVerificationHook, EmailVerificationPlugin, SendVerificationEmail,
273};
274pub use haveibeenpwned::{HaveIBeenPwnedConfig, HaveIBeenPwnedPlugin, PwnedPasswordClient};
275pub use last_login_method::{
276 BeforeStoreLastLoginMethodCookie, LastLoginMethodConfig, LastLoginMethodContext,
277 LastLoginMethodPlugin, ResolveLastLoginMethod,
278};
279pub use magic_link::{MagicLinkConfig, MagicLinkPlugin, SendMagicLink};
280pub use multi_session::{MultiSessionConfig, MultiSessionPlugin};
281pub use oauth::OAuthPlugin;
282pub use oauth_popup::OAuthPopupPlugin;
283pub use oauth_proxy::{OAuthProxyConfig, OAuthProxyPlugin};
284pub use one_tap::{OAuthJwksSource, OneTapClientId, OneTapConfig, OneTapPlugin};
285pub use open_api::{OpenApiConfig, OpenApiPlugin};
286pub use organization::{
287 OrganizationConfig, OrganizationCreatePatch, OrganizationCreatedContext,
288 OrganizationCreationHooks, OrganizationDraftContext, OrganizationMemberCreatePatch,
289 OrganizationMemberDraftContext, OrganizationPlugin,
290};
291#[cfg(feature = "passkey")]
292pub use passkey::{
293 AuthenticationResult, PasskeyAuthenticationAfterVerification, PasskeyAuthenticationConfig,
294 PasskeyAuthenticationContext, PasskeyAuthenticatorSelection, PasskeyConfig, PasskeyExtensions,
295 PasskeyExtensionsResolver, PasskeyOptionsContext, PasskeyPlugin,
296 PasskeyRegistrationAfterVerification, PasskeyRegistrationConfig, PasskeyRegistrationContext,
297 PasskeyRegistrationOverride, PasskeyRegistrationUser, PasskeyUserResolver,
298 VerifiedPasskeyAuthentication, VerifiedPasskeyRegistration,
299};
300pub use password_management::{
301 PasswordManagementConfig, PasswordManagementPlugin, SendResetPassword,
302};
303pub use phone_number::{PhoneNumberConfig, PhoneNumberPlugin, SendPhoneOtp};
304pub use session_management::SessionManagementPlugin;
305pub use siwe::{SiweConfig, SiwePlugin};
306pub use two_factor::{
307 SendTwoFactorOtp, TwoFactorBackupCipher, TwoFactorBackupStorage, TwoFactorConfig,
308 TwoFactorOtpCipher, TwoFactorOtpHasher, TwoFactorOtpStorage, TwoFactorPlugin,
309};
310pub use user_management::{
311 ChangeEmailConfig, DeleteUserConfig, SendChangeEmailConfirmation, UserManagementConfig,
312 UserManagementPlugin,
313};
314
315#[derive(Debug, serde::Serialize, serde::Deserialize)]
316pub(crate) struct StatusResponse {
317 status: bool,
318}