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 oauth2;
73pub mod oauth_popup;
74pub mod oauth_provider;
75pub mod oauth_proxy;
76pub mod one_tap;
77pub mod one_time_token;
78pub mod open_api;
79pub mod organization;
80#[cfg(feature = "passkey")]
81pub mod passkey;
82pub mod password_management;
83mod passwordless_numeric;
84pub mod phone_number;
85pub mod scim;
86pub mod session_management;
87pub mod siwe;
88pub mod sso;
89pub(crate) mod token_crypto;
90pub mod two_factor;
91pub mod user_management;
92
93#[cfg(test)]
95pub(crate) mod test_helpers {
96 use alibi_core::config::AuthConfig;
97 use alibi_core::wire::{SessionView, UserView};
98 use alibi_core::{AuthContext, AuthRequest, CreateSession, CreateUser, HttpMethod};
99 use alibi_seaorm::store::__private_test_support::bundled_schema::BundledSchema;
100 use alibi_seaorm::{Database, SeaOrmStore};
101 use chrono::{Duration, Utc};
102 use std::collections::HashMap;
103 use std::sync::Arc;
104
105 pub type TestDatabase = dyn alibi_core::store::AuthStore<BundledSchema>;
106
107 pub fn create_test_config() -> AuthConfig {
108 AuthConfig::new("test-secret-key-at-least-32-chars-long")
109 }
110
111 pub async fn create_test_database() -> Arc<TestDatabase> {
112 let database = Database::connect("sqlite::memory:")
113 .await
114 .expect("sqlite test database should connect");
115 alibi_seaorm::store::__private_test_support::migrator::run_migrations(&database)
116 .await
117 .expect("sqlite test migrations should run");
118 Arc::new(SeaOrmStore::<BundledSchema>::new(
119 Arc::new(create_test_config()),
120 database,
121 ))
122 }
123
124 pub async fn create_test_context() -> AuthContext<BundledSchema> {
125 create_test_context_with_config(create_test_config()).await
126 }
127
128 pub fn create_test_context_blocking() -> AuthContext<BundledSchema> {
129 tokio::runtime::Builder::new_current_thread()
130 .enable_all()
131 .build()
132 .expect("test runtime should build")
133 .block_on(create_test_context())
134 }
135
136 pub async fn create_test_context_with_config(config: AuthConfig) -> AuthContext<BundledSchema> {
137 let config = Arc::new(config);
138 let database = create_test_database().await;
139 AuthContext::new(config, database)
140 }
141
142 pub async fn create_user(
143 ctx: &AuthContext<impl alibi_core::AuthSchema>,
144 create_user: CreateUser,
145 ) -> UserView {
146 let user = ctx.database.create_user(create_user).await.unwrap();
147 UserView::from(&user)
148 }
149
150 pub async fn create_session(
151 ctx: &AuthContext<impl alibi_core::AuthSchema>,
152 user_id: String,
153 expires_in: Duration,
154 ) -> SessionView {
155 let create_session = CreateSession {
156 additional_fields: alibi_core::field_policy::FieldValues::default(),
157 token: None,
158 active_team_id: None,
159 user_id,
160 expires_at: Utc::now() + expires_in,
161 ip_address: Some("127.0.0.1".to_owned()),
162 user_agent: Some("test-agent".to_owned()),
163 impersonated_by: None,
164 active_organization_id: None,
165 };
166 let session = ctx.database.create_session(create_session).await.unwrap();
167 SessionView::from(&session)
168 }
169
170 pub async fn create_user_and_session(
171 ctx: &AuthContext<impl alibi_core::AuthSchema>,
172 user_data: CreateUser,
173 session_expires_in: Duration,
174 ) -> (UserView, SessionView) {
175 let user = create_user(ctx, user_data).await;
176 let session = create_session(ctx, user.id.clone(), session_expires_in).await;
177 (user, session)
178 }
179
180 pub async fn create_test_context_with_user(
181 create_user: CreateUser,
182 session_expires_in: Duration,
183 ) -> (AuthContext<BundledSchema>, UserView, SessionView) {
184 let ctx = create_test_context().await;
185 let (user, session) = create_user_and_session(&ctx, create_user, session_expires_in).await;
186 (ctx, user, session)
187 }
188
189 pub fn create_auth_request(
190 method: HttpMethod,
191 path: &str,
192 token: Option<&str>,
193 body: Option<Vec<u8>>,
194 query: HashMap<String, String>,
195 ) -> AuthRequest {
196 let mut headers = HashMap::new();
197 if let Some(token) = token {
198 let config = create_test_config();
199 headers.insert(
200 "cookie".to_owned(),
201 format!(
202 "{}={}",
203 config.session.cookie_name,
204 alibi_core::utils::cookie_utils::sign_cookie_value(
205 token,
206 config.current_secret()
207 )
208 ),
209 );
210 }
211
212 AuthRequest::from_parts(method, path.to_owned(), headers, body, query)
213 }
214
215 pub fn create_auth_request_no_query(
216 method: HttpMethod,
217 path: &str,
218 token: Option<&str>,
219 body: Option<Vec<u8>>,
220 ) -> AuthRequest {
221 create_auth_request(method, path, token, body, HashMap::new())
222 }
223
224 pub fn create_auth_json_request_no_query(
225 method: HttpMethod,
226 path: &str,
227 token: Option<&str>,
228 body: Option<serde_json::Value>,
229 ) -> AuthRequest {
230 create_auth_json_request(method, path, token, body, HashMap::new())
231 }
232
233 pub fn create_auth_json_request(
234 method: HttpMethod,
235 path: &str,
236 token: Option<&str>,
237 body: Option<serde_json::Value>,
238 query: HashMap<String, String>,
239 ) -> AuthRequest {
240 let mut req = create_auth_request(
241 method,
242 path,
243 token,
244 body.map(|b| serde_json::to_vec(&b).unwrap()),
245 query,
246 );
247 req.headers
248 .insert("content-type".to_owned(), "application/json".to_owned());
249 req
250 }
251}
252pub use account_management::AccountManagementPlugin;
255pub use admin::{
256 AdminBanUserRequest, AdminBannedUserMessage, AdminBannedUserMessageHandler, AdminConfig,
257 AdminCreateUserRequest, AdminImpersonationResponse, AdminListUsersQuery,
258 AdminListUsersResponse, AdminPermissionRequest, AdminPermissionResponse, AdminPlugin,
259 AdminRoleInput, AdminSetRoleRequest, AdminSetUserPasswordRequest, AdminSuccessResponse,
260 AdminUpdateUserRequest, AdminUserOutput, AdminUserResponse, AdminUserSessionsResponse,
261 RolePermissions,
262};
263pub use alibi_core::PasswordHasher;
264pub use anonymous::{
265 AnonymousConfig, AnonymousIdentity, AnonymousLink, AnonymousPlugin, LinkAnonymousAccount,
266};
267pub use api_key::{
268 ApiKeyCallbackContext, ApiKeyConfig, ApiKeyDefaultPermissions, ApiKeyErrorMessage,
269 ApiKeyGenerationOptions, ApiKeyGenerator, ApiKeyGetter, ApiKeyPermissions, ApiKeyPlugin,
270 ApiKeyValidator, DeleteExpiredApiKeysResponse,
271};
272pub use bearer::{BearerConfig, BearerPlugin};
273pub use captcha::{CaptchaConfig, CaptchaPlugin, CaptchaProvider};
274pub use custom_session::{CustomSessionPlugin, SessionTransform, SessionTransformContext};
275pub use device_authorization::DeviceAuthorizationPlugin;
276pub use email_otp::{EmailOtpConfig, EmailOtpPlugin, SendEmailOtp};
277pub use email_password::{EmailPasswordConfig, EmailPasswordPlugin};
278pub use email_verification::{
279 EmailVerificationConfig, EmailVerificationHook, EmailVerificationPlugin, SendVerificationEmail,
280};
281pub use haveibeenpwned::{HaveIBeenPwnedConfig, HaveIBeenPwnedPlugin, PwnedPasswordClient};
282pub use last_login_method::{
283 BeforeStoreLastLoginMethodCookie, LastLoginMethodConfig, LastLoginMethodContext,
284 LastLoginMethodEndpointResponse, LastLoginMethodPlugin, ResolveLastLoginMethod,
285};
286pub use magic_link::{MagicLinkConfig, MagicLinkPlugin, SendMagicLink};
287pub use multi_session::{MultiSessionConfig, MultiSessionPlugin};
288pub use oauth::OAuthPlugin;
289pub use oauth_popup::OAuthPopupPlugin;
290pub use oauth_provider::{
291 OAuthAuthenticatedClient, OAuthAuthorizationQuery, OAuthClientAssertionInput,
292 OAuthClientAuthenticationOptions, OAuthClientAuthenticationStrategy, OAuthClientDiscovery,
293 OAuthClientIdGenerator, OAuthClientMetadataAbortSignal, OAuthClientMetadataFetchOptions,
294 OAuthClientMetadataFetchResponse, OAuthClientMetadataResourceFetch,
295 OAuthClientPrivilegeContext, OAuthClientPrivileges, OAuthClientSecretCipher,
296 OAuthClientSecretGenerator, OAuthClientSecretHasher, OAuthConsentReference,
297 OAuthConsentReferenceContext, OAuthDecodedRefreshToken, OAuthEndpointRateLimit,
298 OAuthExtensionClaims, OAuthExtensionClientAuthentication, OAuthExtensionGrantHandler,
299 OAuthExtensionGrantInput, OAuthInitialAccessTokenAuthorization, OAuthInitialAccessTokenError,
300 OAuthInitialAccessTokenInput, OAuthInitialAccessTokenValidator, OAuthInteractionContext,
301 OAuthMetadataContributor, OAuthMetadataExtensionInput, OAuthMetadataType, OAuthPostLoginConfig,
302 OAuthPostLoginContext, OAuthPostLoginPolicy, OAuthProviderApi, OAuthProviderConfig,
303 OAuthProviderExtension, OAuthProviderPlugin, OAuthProviderRateLimits,
304 OAuthRedirectUriValidator, OAuthRefreshTokenEncryption, OAuthRefreshTokenFormatter,
305 OAuthRequestUriInput, OAuthRequestUriResolver, OAuthResourceIdentifierValidator,
306 OAuthResourcePrivilegeContext, OAuthResourcePrivileges, OAuthResourceSeedMode,
307 OAuthSelectAccountConfig, OAuthSelectAccountContext, OAuthSelectAccountPolicy,
308 OAuthSignupConfig, OAuthSignupContext, OAuthSignupPolicy, OAuthSignupRedirect,
309 OAuthTokenClaimsContributor, OAuthTokenClaimsInput, OAuthTokenGenerator, OAuthTokenHasher,
310 OAuthTokenIssueParams, OAuthUserInfoClaimsContributor, OAuthUserInfoClaimsInput,
311 OAuthVerifiedClientAssertion, consume_client_assertion,
312};
313pub use oauth_proxy::{OAuthProxyConfig, OAuthProxyPlugin};
314pub use one_tap::{OAuthJwksSource, OneTapClientId, OneTapConfig, OneTapPlugin};
315pub use open_api::{OpenApiConfig, OpenApiPlugin};
316pub use organization::{
317 OrganizationConfig, OrganizationCreatePatch, OrganizationCreatedContext,
318 OrganizationCreationHooks, OrganizationDraftContext, OrganizationMemberCreatePatch,
319 OrganizationMemberDraftContext, OrganizationPlugin,
320};
321#[cfg(feature = "passkey")]
322pub use passkey::{
323 AuthenticationResult, PasskeyAuthenticationAfterVerification, PasskeyAuthenticationConfig,
324 PasskeyAuthenticationContext, PasskeyAuthenticatorSelection, PasskeyConfig, PasskeyExtensions,
325 PasskeyExtensionsResolver, PasskeyOptionsContext, PasskeyPlugin,
326 PasskeyRegistrationAfterVerification, PasskeyRegistrationConfig, PasskeyRegistrationContext,
327 PasskeyRegistrationOverride, PasskeyRegistrationUser, PasskeyUserResolver,
328 VerifiedPasskeyAuthentication, VerifiedPasskeyRegistration,
329};
330pub use password_management::{
331 PasswordManagementConfig, PasswordManagementPlugin, SendResetPassword,
332};
333pub use phone_number::{PhoneNumberConfig, PhoneNumberPlugin, SendPhoneOtp};
334pub use session_management::{GetSessionQuery, GetSessionResponse, SessionManagementPlugin};
335pub use siwe::{SiweConfig, SiwePlugin};
336pub use two_factor::{
337 SendTwoFactorOtp, TwoFactorBackupCipher, TwoFactorBackupStorage, TwoFactorConfig,
338 TwoFactorOtpCipher, TwoFactorOtpHasher, TwoFactorOtpStorage, TwoFactorPlugin,
339};
340pub use user_management::{
341 ChangeEmailConfig, DeleteUserConfig, SendChangeEmailConfirmation, UserManagementConfig,
342 UserManagementPlugin,
343};
344
345#[derive(Debug, serde::Serialize, serde::Deserialize)]
346pub(crate) struct StatusResponse {
347 status: bool,
348}
349
350pub use scim::ScimPlugin;
351pub use sso::{
352 SsoAccountKey, SsoConfig, SsoDefaultProvider, SsoDeprecatedAlgorithmBehavior, SsoKeyResolver,
353 SsoMutationAction, SsoMutationGuard, SsoMutationProvider, SsoOrganizationProvisioning,
354 SsoOrganizationRoleResolver, SsoPlugin, SsoPrivateKey, SsoPrivateKeyContext,
355 SsoPrivateKeyResolver, SsoProtocol, SsoProviderLimit, SsoProviderLimitResolver,
356 SsoProviderMutation, SsoProviderMutationGuard, SsoProvisioner, SsoProvisioningData,
357 SsoResolvedProfile, SsoResolver, SsoRoleResolver, SsoSamlEncryptionPolicy,
358 SsoSamlSigningPolicy, SsoUserProvisioner, SsoUserResolution, SsoUserResolutionInput,
359 SsoUserResolver,
360};