#![warn(missing_docs)]
#![cfg_attr(docsrs, feature(doc_cfg))]
pub mod sessions;
pub mod core;
pub mod auth_info;
pub use auth_info::AuthInfo;
pub mod guard;
pub use guard::{All, Any, Guard, Not, Public};
pub use reinhardt_auth_macros::guard;
pub mod auth_user;
#[allow(deprecated)]
pub use auth_user::{AuthUser, CurrentUser};
pub mod auth_extractors;
pub use auth_extractors::validate_auth_extractors;
pub(crate) const USER_ID_NAMESPACE: uuid::Uuid =
uuid::uuid!("c7a85537-073f-5092-8d10-774e109477c9");
pub(crate) mod internal_user;
pub use core::{
AllowAny, AuthBackend, AuthIdentity, BaseUser, CompositeAuthBackend, FullUser, IsActiveUser,
IsAdminUser, IsAuthenticated, IsAuthenticatedOrReadOnly, PasswordHasher, Permission,
PermissionContext, PermissionsMixin, SuperuserCreator, SuperuserCreatorRegistration,
SuperuserInit, TypedSuperuserCreator, auto_register_superuser_creator, get_superuser_creator,
register_superuser_creator, superuser_creator_for,
};
#[cfg(feature = "argon2-hasher")]
pub use core::Argon2Hasher;
pub use core::permission_operators;
pub mod repository;
pub use repository::{SimpleUserRepository, UserRepository};
pub mod advanced_permissions;
pub mod base_user_manager;
#[cfg_attr(docsrs, doc(cfg(feature = "basic")))]
#[cfg(feature = "basic")]
pub mod basic;
pub mod group_management;
#[cfg(feature = "sessions")]
pub mod handlers;
pub mod ip_permission;
#[cfg(feature = "jwt")]
pub mod jwt;
pub mod mfa;
pub mod model_permissions;
#[cfg(feature = "oauth")]
pub mod oauth2;
pub mod object_permissions;
#[cfg(feature = "database")]
pub mod permission;
#[cfg(feature = "rate-limit")]
pub mod rate_limit_permission;
pub mod remote_user;
pub mod rest_authentication;
#[cfg(feature = "sessions")]
pub mod session;
#[cfg(feature = "social")]
pub mod social;
pub mod time_based_permission;
#[cfg(any(feature = "jwt", feature = "token"))]
pub mod token_blacklist;
#[cfg(any(feature = "jwt", feature = "token"))]
pub mod token_rotation;
#[cfg(any(feature = "jwt", feature = "token"))]
pub mod token_storage;
pub mod user_management;
pub mod settings;
pub use advanced_permissions::{ObjectPermission as AdvancedObjectPermission, RoleBasedPermission};
pub use base_user_manager::BaseUserManager;
#[cfg_attr(docsrs, doc(cfg(feature = "basic")))]
#[cfg(feature = "basic")]
pub use basic::BasicAuthentication as HttpBasicAuth;
pub use group_management::{
CreateGroupData, Group, GroupManagementError, GroupManagementResult, GroupManager,
get_group_manager, register_group_manager,
};
#[cfg(feature = "sessions")]
pub use handlers::{LoginCredentials, LoginHandler, LogoutHandler, SESSION_COOKIE_NAME};
pub use ip_permission::{CidrRange, IpBlacklistPermission, IpWhitelistPermission};
#[cfg(feature = "jwt")]
pub use jwt::{Claims, JwtAuth, JwtError};
pub use mfa::MFAAuthentication as MfaManager;
pub use model_permissions::{
DjangoModelPermissions, DjangoModelPermissionsOrAnonReadOnly, ModelPermission,
};
#[cfg(feature = "oauth")]
pub use oauth2::{
AccessToken, AuthorizationCode, GrantType, InMemoryOAuth2Store, OAuth2Application,
OAuth2Authentication, OAuth2TokenStore,
};
pub use object_permissions::{ObjectPermission, ObjectPermissionChecker, ObjectPermissionManager};
#[cfg(feature = "database")]
pub use permission::AuthPermission;
pub use permission_operators::{AndPermission, NotPermission, OrPermission};
pub use reinhardt_core::exception::Error as BaseUserManagerError;
pub use serde_json::Value as JsonValue;
#[cfg(feature = "social")]
pub use social::{
AppleProvider, GenericOidcConfig, GenericOidcProvider, GitHubProvider, GoogleProvider, IdToken,
MicrosoftProvider, OAuthProvider, OAuthToken, PkceFlow, ProviderConfig, SocialAuthBackend,
SocialAuthError, StandardClaims, StateStore, TokenResponse, UserInfoMapper,
};
#[cfg(feature = "rate-limit")]
pub use rate_limit_permission::{RateLimitPermission, RateLimitPermissionBuilder};
pub use remote_user::RemoteUserAuthentication as RemoteUserAuth;
pub use rest_authentication::{
BasicAuthConfig, CompositeAuthentication, RemoteUserAuthentication, RestAuthentication,
SessionAuthConfig, SessionAuthentication, TokenAuthConfig, TokenAuthentication,
};
#[cfg(feature = "sessions")]
pub use session::{InMemorySessionStore, SESSION_KEY_USER_ID, Session, SessionId, SessionStore};
pub use time_based_permission::{DateRange, TimeBasedPermission, TimeWindow};
#[cfg(any(feature = "jwt", feature = "token"))]
pub use token_blacklist::{
BlacklistReason, BlacklistStats, BlacklistedToken, InMemoryRefreshTokenStore,
InMemoryTokenBlacklist, RefreshToken, RefreshTokenStore, TokenBlacklist, TokenRotationManager,
};
#[cfg(any(feature = "jwt", feature = "token"))]
#[allow(deprecated)] pub use token_rotation::{AutoTokenRotationManager, TokenRotationConfig, TokenRotationRecord};
#[cfg(feature = "sessions")]
pub use settings::SessionSettings;
#[cfg(feature = "jwt")]
pub use settings::{JwtSessionSettings, create_jwt_session_backend_from_settings};
#[cfg(feature = "token")]
pub use settings::{TokenRotationSettings, create_token_rotation_manager_from_settings};
#[cfg(all(feature = "database", any(feature = "jwt", feature = "token")))]
pub use token_storage::DatabaseTokenStorage;
#[cfg(any(feature = "jwt", feature = "token"))]
pub use token_storage::{
InMemoryTokenStorage, StoredToken, TokenStorage, TokenStorageError, TokenStorageResult,
};
pub use user_management::{
CreateUserData, ManagedUser, UpdateUserData, UserManagementError, UserManagementResult,
UserManager,
};
#[non_exhaustive]
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum AuthenticationError {
InvalidCredentials,
UserNotFound,
SessionExpired,
InvalidToken,
TokenExpired,
NotAuthenticated,
DatabaseError(String),
Unknown(String),
}
impl std::fmt::Display for AuthenticationError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
AuthenticationError::InvalidCredentials => write!(f, "Invalid credentials"),
AuthenticationError::UserNotFound => write!(f, "User not found"),
AuthenticationError::SessionExpired => write!(f, "Session expired"),
AuthenticationError::InvalidToken => write!(f, "Invalid token"),
AuthenticationError::TokenExpired => write!(f, "Token expired"),
AuthenticationError::NotAuthenticated => write!(f, "User is not authenticated"),
AuthenticationError::DatabaseError(msg) => write!(f, "Database error: {}", msg),
AuthenticationError::Unknown(msg) => write!(f, "Authentication error: {}", msg),
}
}
}
impl std::error::Error for AuthenticationError {}
#[cfg(feature = "jwt")]
impl From<JwtError> for AuthenticationError {
fn from(err: JwtError) -> Self {
match err {
JwtError::TokenExpired => AuthenticationError::TokenExpired,
JwtError::InvalidSignature(_) | JwtError::InvalidToken(_) => {
AuthenticationError::InvalidToken
}
JwtError::EncodingError(msg) => AuthenticationError::Unknown(msg),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
#[cfg(feature = "jwt")]
fn test_auth_jwt_generate_unit() {
let jwt_auth = JwtAuth::new(b"test_secret_key");
let user_id = "user123".to_string();
let username = "testuser".to_string();
let token = jwt_auth
.generate_token(user_id, username, false, false)
.unwrap();
assert!(!token.is_empty());
}
#[tokio::test]
async fn test_permission_allow_any() {
use bytes::Bytes;
use hyper::Method;
use reinhardt_http::Request;
let permission = AllowAny;
let request = Request::builder()
.method(Method::GET)
.uri("/test")
.body(Bytes::new())
.build()
.unwrap();
let context = PermissionContext {
request: &request,
is_authenticated: false,
is_admin: false,
is_active: false,
user: None,
};
assert!(permission.has_permission(&context).await);
}
#[tokio::test]
async fn test_permission_is_authenticated_with_auth() {
use bytes::Bytes;
use hyper::Method;
use reinhardt_http::Request;
let permission = IsAuthenticated;
let request = Request::builder()
.method(Method::GET)
.uri("/test")
.body(Bytes::new())
.build()
.unwrap();
let context = PermissionContext {
request: &request,
is_authenticated: true,
is_admin: false,
is_active: true,
user: None,
};
assert!(permission.has_permission(&context).await);
}
#[tokio::test]
async fn test_permission_is_authenticated_without_auth() {
use bytes::Bytes;
use hyper::Method;
use reinhardt_http::Request;
let permission = IsAuthenticated;
let request = Request::builder()
.method(Method::GET)
.uri("/test")
.body(Bytes::new())
.build()
.unwrap();
let context = PermissionContext {
request: &request,
is_authenticated: false,
is_admin: false,
is_active: false,
user: None,
};
assert!(!permission.has_permission(&context).await);
}
#[tokio::test]
async fn test_permission_is_admin_user() {
use bytes::Bytes;
use hyper::Method;
use reinhardt_http::Request;
let permission = IsAdminUser;
let request = Request::builder()
.method(Method::GET)
.uri("/test")
.body(Bytes::new())
.build()
.unwrap();
let context = PermissionContext {
request: &request,
is_authenticated: true,
is_admin: true,
is_active: true,
user: None,
};
assert!(permission.has_permission(&context).await);
let context = PermissionContext {
request: &request,
is_authenticated: true,
is_admin: false,
is_active: true,
user: None,
};
assert!(!permission.has_permission(&context).await);
}
#[tokio::test]
async fn test_permission_is_active_user() {
use bytes::Bytes;
use hyper::Method;
use reinhardt_http::Request;
let permission = IsActiveUser;
let request = Request::builder()
.method(Method::GET)
.uri("/test")
.body(Bytes::new())
.build()
.unwrap();
let context = PermissionContext {
request: &request,
is_authenticated: true,
is_admin: false,
is_active: true,
user: None,
};
assert!(permission.has_permission(&context).await);
let context = PermissionContext {
request: &request,
is_authenticated: true,
is_admin: false,
is_active: false,
user: None,
};
assert!(!permission.has_permission(&context).await);
}
#[tokio::test]
async fn test_permission_is_authenticated_or_read_only_get() {
use bytes::Bytes;
use hyper::Method;
use reinhardt_http::Request;
let permission = IsAuthenticatedOrReadOnly;
let request = Request::builder()
.method(Method::GET)
.uri("/test")
.body(Bytes::new())
.build()
.unwrap();
let context = PermissionContext {
request: &request,
is_authenticated: false,
is_admin: false,
is_active: false,
user: None,
};
assert!(permission.has_permission(&context).await);
}
#[tokio::test]
async fn test_permission_is_authenticated_or_read_only_post() {
use bytes::Bytes;
use hyper::Method;
use reinhardt_http::Request;
let permission = IsAuthenticatedOrReadOnly;
let request = Request::builder()
.method(Method::POST)
.uri("/test")
.body(Bytes::new())
.build()
.unwrap();
let context = PermissionContext {
request: &request,
is_authenticated: false,
is_admin: false,
is_active: false,
user: None,
};
assert!(!permission.has_permission(&context).await);
let context = PermissionContext {
request: &request,
is_authenticated: true,
is_admin: false,
is_active: true,
user: None,
};
assert!(permission.has_permission(&context).await);
}
}