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