pub mod config;
pub mod interface;
#[cfg(feature = "http")]
pub mod middleware;
pub mod types;
pub use garrison::prelude::{GarrisonConfig, GarrisonManager, GarrisonUtil};
pub use config::map_auth_config_to_garrison;
pub use interface::VecBoostInterface;
#[derive(Clone, Debug)]
pub struct GarrisonHandle {
pub admin_password_hash: Option<String>,
pub admin_username: String,
pub token_timeout_secs: i64,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum LoginDecision {
Authenticated,
InvalidCredentials,
AdminPasswordMissing,
}
pub fn verify_login_decision(
handle: &GarrisonHandle,
username: &str,
password: &str,
) -> LoginDecision {
if username != handle.admin_username {
return LoginDecision::InvalidCredentials;
}
let Some(ref hash) = handle.admin_password_hash else {
return LoginDecision::AdminPasswordMissing;
};
match garrison::account::credential::password::PasswordVerifier::verify(password, hash) {
Ok(true) => LoginDecision::Authenticated,
Ok(false) | Err(_) => LoginDecision::InvalidCredentials,
}
}
pub use types::{AuthResponse, LoginRequest, RefreshTokenRequest, User, validate_username_format};
pub use garrison::account::credential::password::{Argon2Hasher, PasswordHasher};
#[cfg(feature = "auth")]
pub use garrison::web::csrf::{
CsrfConfig as GarrisonCsrfConfig, generate_csrf_token, validate_csrf_token,
};
#[cfg(feature = "auth")]
pub use garrison::web::csrf::garrison_csrf_middleware;
#[cfg(feature = "auth")]
pub use garrison::stp::with_current_token;
#[cfg(feature = "auth")]
pub use garrison::dao::GarrisonDaoOxcache;
#[cfg(feature = "auth")]
pub use garrison::{AnomalousConfig, AnomalousLoginStrategy};
#[cfg(feature = "auth")]
pub use garrison::{BruteForceConfig, BruteForceStrategy};
#[cfg(feature = "auth")]
pub use garrison::{DDoSConfig, DDoSStrategy};
#[cfg(feature = "auth")]
pub use garrison::{FirewallContext, GarrisonFirewallStrategy, StrategyRegistration};
#[cfg(feature = "auth")]
pub use garrison::{RateLimitConfig, RateLimitScope, RateLimitStrategy};
#[cfg(feature = "auth")]
pub use garrison::backend::{BackendKitError, BackendModule};
#[cfg(feature = "auth")]
pub use garrison::secure::TotpVerifier;
#[cfg(feature = "http")]
pub use middleware::{
auth_middleware, auth_rate_limit_middleware, optional_auth_middleware,
require_permission_middleware, require_role_middleware,
};
#[cfg(test)]
mod tests {
use super::*;
use garrison::account::credential::password::PasswordVerifier;
#[test]
fn argon2_hash_then_verify_correct_password() {
let password = "secure_admin_pass";
let hash = Argon2Hasher::default()
.hash(password)
.expect("hash must succeed");
assert!(hash.starts_with("$argon2"));
let ok = PasswordVerifier::verify(password, &hash).expect("verify must succeed");
assert!(ok, "correct password must verify");
}
#[test]
fn argon2_hash_then_verify_wrong_password() {
let password = "correct_password";
let hash = Argon2Hasher::default()
.hash(password)
.expect("hash must succeed");
let ok = PasswordVerifier::verify("wrong_password", &hash).expect("verify must succeed");
assert!(!ok, "wrong password must not verify");
}
#[test]
fn garrison_handle_with_password_hash() {
let hash = Argon2Hasher::default()
.hash("test_pw")
.expect("hash must succeed");
let handle = GarrisonHandle {
admin_password_hash: Some(hash.clone()),
admin_username: "admin".to_string(),
token_timeout_secs: 7200,
};
assert_eq!(handle.token_timeout_secs, 7200);
assert!(handle.admin_password_hash.is_some());
let ok = PasswordVerifier::verify("test_pw", handle.admin_password_hash.as_ref().unwrap())
.expect("verify must succeed");
assert!(ok);
}
#[test]
fn garrison_handle_without_password_hash() {
let handle = GarrisonHandle {
admin_password_hash: None,
admin_username: "admin".to_string(),
token_timeout_secs: 3600,
};
assert!(handle.admin_password_hash.is_none());
assert_eq!(handle.token_timeout_secs, 3600);
}
fn handle_with_password() -> GarrisonHandle {
let hash = Argon2Hasher::default()
.hash("Correct-Admin-Pw-1")
.expect("hash must succeed");
GarrisonHandle {
admin_password_hash: Some(hash),
admin_username: "admin".to_string(),
token_timeout_secs: 3600,
}
}
#[test]
fn admin_correct_password_authenticates() {
let h = handle_with_password();
assert_eq!(
verify_login_decision(&h, "admin", "Correct-Admin-Pw-1"),
LoginDecision::Authenticated
);
}
#[test]
fn non_admin_username_rejected_even_with_valid_password() {
let h = handle_with_password();
assert_eq!(
verify_login_decision(&h, "root", "Correct-Admin-Pw-1"),
LoginDecision::InvalidCredentials
);
}
#[test]
fn admin_wrong_password_rejected() {
let h = handle_with_password();
assert_eq!(
verify_login_decision(&h, "admin", "wrong-password"),
LoginDecision::InvalidCredentials
);
}
#[test]
fn missing_password_hash_maps_to_unavailable() {
let h = GarrisonHandle {
admin_password_hash: None,
admin_username: "admin".to_string(),
token_timeout_secs: 3600,
};
assert_eq!(
verify_login_decision(&h, "admin", "anything"),
LoginDecision::AdminPasswordMissing
);
}
}