#![doc(html_root_url = "https://docs.rs/ntex-basicauth/")]
#![warn(missing_docs)]
#![warn(clippy::all)]
#![forbid(unsafe_code)]
mod auth;
mod error;
mod utils;
#[cfg(feature = "cache")]
mod cache;
pub use auth::{BasicAuth, BasicAuthConfig, Credentials, StaticUserValidator, UserValidator};
pub use error::{AuthError, AuthResult};
pub use utils::{
BasicAuthBuilder, PathFilter, common_skip_paths, extract_credentials, extract_credentials_web,
get_username, is_user, is_valid_username,
};
#[cfg(feature = "bcrypt")]
pub use auth::BcryptUserValidator;
#[cfg(feature = "cache")]
pub use cache::{AuthCache, CacheConfig, CacheStats};
pub use auth::BasicAuth as BasicAuthMiddleware;
pub mod prelude {
pub use crate::{
AuthError, AuthResult, BasicAuth, BasicAuthBuilder, BasicAuthConfig, Credentials,
PathFilter, StaticUserValidator, UserValidator, extract_credentials, get_username, is_user,
};
#[cfg(feature = "bcrypt")]
pub use crate::BcryptUserValidator;
#[cfg(feature = "cache")]
pub use crate::{AuthCache, CacheConfig};
}
pub fn single_user_auth(username: &str, password: &str, realm: &str) -> AuthResult<BasicAuth> {
BasicAuthBuilder::new()
.user(username, password)
.realm(realm)
.build()
}
pub fn multi_user_auth(
users: std::collections::HashMap<String, String>,
realm: &str,
) -> AuthResult<BasicAuth> {
BasicAuthBuilder::new().users(users).realm(realm).build()
}
pub fn auth_with_common_skips(
users: std::collections::HashMap<String, String>,
realm: &str,
) -> AuthResult<BasicAuth> {
BasicAuthBuilder::new()
.users(users)
.realm(realm)
.path_filter(common_skip_paths())
.build()
}
#[cfg(feature = "bcrypt")]
pub fn bcrypt_auth(
users: std::collections::HashMap<String, String>,
realm: &str,
) -> AuthResult<BasicAuth> {
let validator = std::sync::Arc::new(auth::BcryptUserValidator::from_hashes(users));
let config = BasicAuthConfig::new(validator).realm(realm.to_string());
BasicAuth::new(config)
}
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
pub fn version() -> &'static str {
VERSION
}
pub struct LibInfo {
pub version: &'static str,
pub name: &'static str,
pub description: &'static str,
pub authors: &'static str,
pub enabled_features: Vec<&'static str>,
}
pub fn lib_info() -> LibInfo {
let mut features = Vec::new();
#[cfg(feature = "json")]
features.push("json");
#[cfg(feature = "cache")]
features.push("cache");
#[cfg(feature = "regex")]
features.push("regex");
#[cfg(feature = "timing-safe")]
features.push("timing-safe");
#[cfg(feature = "bcrypt")]
features.push("bcrypt");
LibInfo {
version: VERSION,
name: env!("CARGO_PKG_NAME"),
description: env!("CARGO_PKG_DESCRIPTION"),
authors: env!("CARGO_PKG_AUTHORS"),
enabled_features: features,
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::collections::HashMap;
#[tokio::test]
async fn test_single_user_auth() {
let auth = single_user_auth("admin", "secret", "Test").unwrap();
assert_eq!(auth.config.realm, "Test");
}
#[tokio::test]
async fn test_multi_user_auth() {
let mut users = HashMap::new();
users.insert("admin".to_string(), "secret".to_string());
users.insert("user".to_string(), "password".to_string());
let auth = multi_user_auth(users, "Test App").unwrap();
assert_eq!(auth.config.realm, "Test App");
}
#[tokio::test]
async fn test_auth_with_common_skips() {
let mut users = HashMap::new();
users.insert("admin".to_string(), "secret".to_string());
let auth = auth_with_common_skips(users, "Test").unwrap();
assert!(auth.config.path_filter.is_some());
let filter = auth.config.path_filter.as_ref().unwrap();
assert!(filter.should_skip("/health"));
assert!(filter.should_skip("/static/css/main.css"));
assert!(!filter.should_skip("/api/users"));
}
#[cfg(feature = "bcrypt")]
#[tokio::test]
async fn test_bcrypt_auth() {
let mut users = HashMap::new();
users.insert(
"admin".to_string(),
"$2b$12$LQv3c1yqBWVHxkd0LHAkCOYz6TtxMQJqhN8/LewdBPj6QJEo4m7HS".to_string(),
);
let auth = bcrypt_auth(users, "Test").unwrap();
assert_eq!(auth.config.realm, "Test");
}
#[test]
fn test_version_info() {
let version = version();
assert!(!version.is_empty());
let info = lib_info();
assert_eq!(info.version, version);
assert_eq!(info.name, "ntex-basicauth");
assert!(!info.enabled_features.is_empty());
}
#[test]
fn test_lib_info_features() {
let info = lib_info();
assert!(info.enabled_features.contains(&"json"));
assert!(info.enabled_features.contains(&"cache"));
assert!(info.enabled_features.contains(&"regex"));
assert!(info.enabled_features.contains(&"timing-safe"));
println!("Enabled features: {:?}", info.enabled_features);
}
#[test]
fn test_prelude_imports() {
use crate::prelude::*;
let _builder = BasicAuthBuilder::new();
let _filter = PathFilter::new();
let _error = AuthError::MissingHeader;
}
}
#[cfg(doctest)]
mod doctests {
fn _basic_usage() {}
#[cfg(feature = "cache")]
fn _advanced_config() {}
#[cfg(feature = "cache")]
fn _cache_config() {}
}