1#![warn(missing_docs)]
2#![cfg_attr(docsrs, feature(doc_cfg))]
3pub mod sessions;
62
63pub mod core;
65
66pub mod auth_info;
68pub use auth_info::AuthInfo;
69
70pub mod guard;
73pub use guard::{All, Any, Guard, Not, Public};
74
75pub use reinhardt_auth_macros::guard;
77
78pub mod auth_user;
80#[allow(deprecated)]
81pub use auth_user::{AuthUser, CurrentUser};
82
83pub mod auth_extractors;
85pub use auth_extractors::validate_auth_extractors;
86
87pub(crate) const USER_ID_NAMESPACE: uuid::Uuid =
91 uuid::uuid!("c7a85537-073f-5092-8d10-774e109477c9");
92
93pub(crate) mod internal_user;
94
95pub use core::{
100 AllowAny, AuthBackend, AuthIdentity, BaseUser, CompositeAuthBackend, FullUser, IsActiveUser,
101 IsAdminUser, IsAuthenticated, IsAuthenticatedOrReadOnly, PasswordHasher, Permission,
102 PermissionContext, PermissionsMixin, SuperuserCreator, SuperuserCreatorRegistration,
103 SuperuserInit, TypedSuperuserCreator, auto_register_superuser_creator, get_superuser_creator,
104 register_superuser_creator, superuser_creator_for,
105};
106
107#[cfg(feature = "argon2-hasher")]
108pub use core::Argon2Hasher;
109
110pub use core::permission_operators;
112
113pub mod repository;
114pub use repository::{SimpleUserRepository, UserRepository};
115
116pub mod advanced_permissions;
118pub mod base_user_manager;
120#[cfg_attr(docsrs, doc(cfg(feature = "basic")))]
122#[cfg(feature = "basic")]
123pub mod basic;
124pub mod group_management;
126#[cfg(feature = "sessions")]
128pub mod handlers;
129pub mod ip_permission;
131#[cfg(feature = "jwt")]
133pub mod jwt;
134pub mod mfa;
136pub mod model_permissions;
138#[cfg(feature = "oauth")]
140pub mod oauth2;
141pub mod object_permissions;
143#[cfg(feature = "database")]
145pub mod permission;
146#[cfg(feature = "rate-limit")]
148pub mod rate_limit_permission;
149pub mod remote_user;
151pub mod rest_authentication;
153#[cfg(feature = "sessions")]
155pub mod session;
156#[cfg(feature = "social")]
158pub mod social;
159pub mod time_based_permission;
161#[cfg(any(feature = "jwt", feature = "token"))]
163pub mod token_blacklist;
164#[cfg(any(feature = "jwt", feature = "token"))]
166pub mod token_rotation;
167#[cfg(any(feature = "jwt", feature = "token"))]
169pub mod token_storage;
170pub mod user_management;
172
173pub mod settings;
175
176pub use advanced_permissions::{ObjectPermission as AdvancedObjectPermission, RoleBasedPermission};
177pub use base_user_manager::BaseUserManager;
178#[cfg_attr(docsrs, doc(cfg(feature = "basic")))]
179#[cfg(feature = "basic")]
180pub use basic::BasicAuthentication as HttpBasicAuth;
181pub use group_management::{
182 CreateGroupData, Group, GroupManagementError, GroupManagementResult, GroupManager,
183 get_group_manager, register_group_manager,
184};
185#[cfg(feature = "sessions")]
186pub use handlers::{LoginCredentials, LoginHandler, LogoutHandler, SESSION_COOKIE_NAME};
187pub use ip_permission::{CidrRange, IpBlacklistPermission, IpWhitelistPermission};
188#[cfg(feature = "jwt")]
189pub use jwt::{Claims, JwtAuth, JwtError};
190pub use mfa::MFAAuthentication as MfaManager;
191pub use model_permissions::{
192 DjangoModelPermissions, DjangoModelPermissionsOrAnonReadOnly, ModelPermission,
193};
194#[cfg(feature = "oauth")]
195pub use oauth2::{
196 AccessToken, AuthorizationCode, GrantType, InMemoryOAuth2Store, OAuth2Application,
197 OAuth2Authentication, OAuth2TokenStore,
198};
199pub use object_permissions::{ObjectPermission, ObjectPermissionChecker, ObjectPermissionManager};
200#[cfg(feature = "database")]
201pub use permission::AuthPermission;
202pub use permission_operators::{AndPermission, NotPermission, OrPermission};
203pub use reinhardt_core::exception::Error as BaseUserManagerError;
207
208pub use serde_json::Value as JsonValue;
215#[cfg(feature = "social")]
216pub use social::{
217 AppleProvider, GenericOidcConfig, GenericOidcProvider, GitHubProvider, GoogleProvider, IdToken,
218 MicrosoftProvider, OAuthProvider, OAuthToken, PkceFlow, ProviderConfig, SocialAuthBackend,
219 SocialAuthError, StandardClaims, StateStore, TokenResponse, UserInfoMapper,
220};
221
222#[cfg(feature = "rate-limit")]
223pub use rate_limit_permission::{RateLimitPermission, RateLimitPermissionBuilder};
224pub use remote_user::RemoteUserAuthentication as RemoteUserAuth;
225pub use rest_authentication::{
226 BasicAuthConfig, CompositeAuthentication, RemoteUserAuthentication, RestAuthentication,
227 SessionAuthConfig, SessionAuthentication, TokenAuthConfig, TokenAuthentication,
228};
229#[cfg(feature = "sessions")]
230pub use session::{InMemorySessionStore, SESSION_KEY_USER_ID, Session, SessionId, SessionStore};
231pub use time_based_permission::{DateRange, TimeBasedPermission, TimeWindow};
232#[cfg(any(feature = "jwt", feature = "token"))]
233pub use token_blacklist::{
234 BlacklistReason, BlacklistStats, BlacklistedToken, InMemoryRefreshTokenStore,
235 InMemoryTokenBlacklist, RefreshToken, RefreshTokenStore, TokenBlacklist, TokenRotationManager,
236};
237#[cfg(any(feature = "jwt", feature = "token"))]
238#[allow(deprecated)] pub use token_rotation::{AutoTokenRotationManager, TokenRotationConfig, TokenRotationRecord};
240
241#[cfg(feature = "sessions")]
242pub use settings::SessionSettings;
243
244#[cfg(feature = "jwt")]
245pub use settings::{JwtSessionSettings, create_jwt_session_backend_from_settings};
246
247#[cfg(feature = "token")]
248pub use settings::{TokenRotationSettings, create_token_rotation_manager_from_settings};
249#[cfg(all(feature = "database", any(feature = "jwt", feature = "token")))]
250pub use token_storage::DatabaseTokenStorage;
251#[cfg(any(feature = "jwt", feature = "token"))]
252pub use token_storage::{
253 InMemoryTokenStorage, StoredToken, TokenStorage, TokenStorageError, TokenStorageResult,
254};
255pub use user_management::{
256 CreateUserData, ManagedUser, UpdateUserData, UserManagementError, UserManagementResult,
257 UserManager,
258};
259
260#[non_exhaustive]
262#[derive(Debug, Clone, PartialEq, Eq)]
263pub enum AuthenticationError {
264 InvalidCredentials,
266 UserNotFound,
268 SessionExpired,
270 InvalidToken,
272 TokenExpired,
274 NotAuthenticated,
276 DatabaseError(String),
278 Unknown(String),
280}
281
282impl std::fmt::Display for AuthenticationError {
283 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
284 match self {
285 AuthenticationError::InvalidCredentials => write!(f, "Invalid credentials"),
286 AuthenticationError::UserNotFound => write!(f, "User not found"),
287 AuthenticationError::SessionExpired => write!(f, "Session expired"),
288 AuthenticationError::InvalidToken => write!(f, "Invalid token"),
289 AuthenticationError::TokenExpired => write!(f, "Token expired"),
290 AuthenticationError::NotAuthenticated => write!(f, "User is not authenticated"),
291 AuthenticationError::DatabaseError(msg) => write!(f, "Database error: {}", msg),
292 AuthenticationError::Unknown(msg) => write!(f, "Authentication error: {}", msg),
293 }
294 }
295}
296
297impl std::error::Error for AuthenticationError {}
298
299#[cfg(feature = "jwt")]
300impl From<JwtError> for AuthenticationError {
301 fn from(err: JwtError) -> Self {
302 match err {
303 JwtError::TokenExpired => AuthenticationError::TokenExpired,
304 JwtError::InvalidSignature(_) | JwtError::InvalidToken(_) => {
305 AuthenticationError::InvalidToken
306 }
307 JwtError::EncodingError(msg) => AuthenticationError::Unknown(msg),
308 }
309 }
310}
311
312#[cfg(test)]
318mod tests {
319 use super::*;
320
321 #[test]
322 #[cfg(feature = "jwt")]
323 fn test_auth_jwt_generate_unit() {
324 let jwt_auth = JwtAuth::new(b"test_secret_key");
325 let user_id = "user123".to_string();
326 let username = "testuser".to_string();
327
328 let token = jwt_auth
329 .generate_token(user_id, username, false, false)
330 .unwrap();
331
332 assert!(!token.is_empty());
333 }
334
335 #[tokio::test]
336 async fn test_permission_allow_any() {
337 use bytes::Bytes;
338 use hyper::Method;
339 use reinhardt_http::Request;
340
341 let permission = AllowAny;
342 let request = Request::builder()
343 .method(Method::GET)
344 .uri("/test")
345 .body(Bytes::new())
346 .build()
347 .unwrap();
348
349 let context = PermissionContext {
350 request: &request,
351 is_authenticated: false,
352 is_admin: false,
353 is_active: false,
354 user: None,
355 };
356
357 assert!(permission.has_permission(&context).await);
358 }
359
360 #[tokio::test]
361 async fn test_permission_is_authenticated_with_auth() {
362 use bytes::Bytes;
363 use hyper::Method;
364 use reinhardt_http::Request;
365
366 let permission = IsAuthenticated;
367 let request = Request::builder()
368 .method(Method::GET)
369 .uri("/test")
370 .body(Bytes::new())
371 .build()
372 .unwrap();
373
374 let context = PermissionContext {
375 request: &request,
376 is_authenticated: true,
377 is_admin: false,
378 is_active: true,
379 user: None,
380 };
381
382 assert!(permission.has_permission(&context).await);
383 }
384
385 #[tokio::test]
386 async fn test_permission_is_authenticated_without_auth() {
387 use bytes::Bytes;
388 use hyper::Method;
389 use reinhardt_http::Request;
390
391 let permission = IsAuthenticated;
392 let request = Request::builder()
393 .method(Method::GET)
394 .uri("/test")
395 .body(Bytes::new())
396 .build()
397 .unwrap();
398
399 let context = PermissionContext {
400 request: &request,
401 is_authenticated: false,
402 is_admin: false,
403 is_active: false,
404 user: None,
405 };
406
407 assert!(!permission.has_permission(&context).await);
408 }
409
410 #[tokio::test]
411 async fn test_permission_is_admin_user() {
412 use bytes::Bytes;
413 use hyper::Method;
414 use reinhardt_http::Request;
415
416 let permission = IsAdminUser;
417 let request = Request::builder()
418 .method(Method::GET)
419 .uri("/test")
420 .body(Bytes::new())
421 .build()
422 .unwrap();
423
424 let context = PermissionContext {
426 request: &request,
427 is_authenticated: true,
428 is_admin: true,
429 is_active: true,
430 user: None,
431 };
432 assert!(permission.has_permission(&context).await);
433
434 let context = PermissionContext {
436 request: &request,
437 is_authenticated: true,
438 is_admin: false,
439 is_active: true,
440 user: None,
441 };
442 assert!(!permission.has_permission(&context).await);
443 }
444
445 #[tokio::test]
446 async fn test_permission_is_active_user() {
447 use bytes::Bytes;
448 use hyper::Method;
449 use reinhardt_http::Request;
450
451 let permission = IsActiveUser;
452 let request = Request::builder()
453 .method(Method::GET)
454 .uri("/test")
455 .body(Bytes::new())
456 .build()
457 .unwrap();
458
459 let context = PermissionContext {
461 request: &request,
462 is_authenticated: true,
463 is_admin: false,
464 is_active: true,
465 user: None,
466 };
467 assert!(permission.has_permission(&context).await);
468
469 let context = PermissionContext {
471 request: &request,
472 is_authenticated: true,
473 is_admin: false,
474 is_active: false,
475 user: None,
476 };
477 assert!(!permission.has_permission(&context).await);
478 }
479
480 #[tokio::test]
481 async fn test_permission_is_authenticated_or_read_only_get() {
482 use bytes::Bytes;
483 use hyper::Method;
484 use reinhardt_http::Request;
485
486 let permission = IsAuthenticatedOrReadOnly;
487 let request = Request::builder()
488 .method(Method::GET)
489 .uri("/test")
490 .body(Bytes::new())
491 .build()
492 .unwrap();
493
494 let context = PermissionContext {
496 request: &request,
497 is_authenticated: false,
498 is_admin: false,
499 is_active: false,
500 user: None,
501 };
502 assert!(permission.has_permission(&context).await);
503 }
504
505 #[tokio::test]
506 async fn test_permission_is_authenticated_or_read_only_post() {
507 use bytes::Bytes;
508 use hyper::Method;
509 use reinhardt_http::Request;
510
511 let permission = IsAuthenticatedOrReadOnly;
512 let request = Request::builder()
513 .method(Method::POST)
514 .uri("/test")
515 .body(Bytes::new())
516 .build()
517 .unwrap();
518
519 let context = PermissionContext {
521 request: &request,
522 is_authenticated: false,
523 is_admin: false,
524 is_active: false,
525 user: None,
526 };
527 assert!(!permission.has_permission(&context).await);
528
529 let context = PermissionContext {
531 request: &request,
532 is_authenticated: true,
533 is_admin: false,
534 is_active: true,
535 user: None,
536 };
537 assert!(permission.has_permission(&context).await);
538 }
539}