#![allow(deprecated)]
#[cfg(any(feature = "sessions", feature = "jwt", feature = "token"))]
use serde::{Deserialize, Serialize};
#[cfg(feature = "sessions")]
mod session_settings {
use super::*;
use crate::sessions::config::{SameSite, SessionConfig};
use reinhardt_core::macros::settings;
use std::time::Duration;
fn default_cookie_name() -> String {
"sessionid".to_string()
}
fn default_cookie_path() -> String {
"/".to_string()
}
fn default_cookie_secure() -> bool {
true
}
fn default_cookie_httponly() -> bool {
true
}
fn default_cookie_samesite() -> String {
"lax".to_string()
}
fn parse_samesite(value: &str) -> SameSite {
match value.to_ascii_lowercase().as_str() {
"strict" => SameSite::Strict,
"none" => SameSite::None,
_ => SameSite::Lax,
}
}
#[settings(fragment = true, section = "auth_session")]
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct SessionSettings {
#[serde(default = "default_cookie_name")]
pub cookie_name: String,
#[serde(default)]
pub cookie_age_secs: Option<u64>,
#[serde(default = "default_cookie_path")]
pub cookie_path: String,
#[serde(default)]
pub cookie_domain: Option<String>,
#[serde(default = "default_cookie_secure")]
pub cookie_secure: bool,
#[serde(default = "default_cookie_httponly")]
pub cookie_httponly: bool,
#[serde(default = "default_cookie_samesite")]
pub cookie_samesite: String,
#[serde(default)]
pub save_every_request: bool,
}
impl Default for SessionSettings {
fn default() -> Self {
Self {
cookie_name: default_cookie_name(),
cookie_age_secs: None,
cookie_path: default_cookie_path(),
cookie_domain: None,
cookie_secure: default_cookie_secure(),
cookie_httponly: default_cookie_httponly(),
cookie_samesite: default_cookie_samesite(),
save_every_request: false,
}
}
}
impl SessionSettings {
pub fn to_config(&self) -> SessionConfig {
let mut builder = SessionConfig::builder()
.cookie_name(self.cookie_name.clone())
.cookie_path(self.cookie_path.clone())
.cookie_secure(self.cookie_secure)
.cookie_httponly(self.cookie_httponly)
.cookie_samesite(parse_samesite(&self.cookie_samesite))
.save_every_request(self.save_every_request);
if let Some(secs) = self.cookie_age_secs {
builder = builder.cookie_age(Duration::from_secs(secs));
}
if let Some(domain) = &self.cookie_domain {
builder = builder.cookie_domain(domain.clone());
}
builder.build()
}
}
impl From<&SessionSettings> for SessionConfig {
fn from(settings: &SessionSettings) -> Self {
settings.to_config()
}
}
}
#[cfg(feature = "sessions")]
pub use session_settings::SessionSettings;
#[cfg(feature = "jwt")]
mod jwt_session_settings {
use super::*;
use crate::sessions::backends::jwt::{JwtConfig, JwtSessionBackend, JwtSessionError};
use jsonwebtoken::Algorithm;
use reinhardt_core::macros::settings;
fn default_algorithm() -> String {
"HS256".to_string()
}
fn default_expiration() -> u64 {
3600 }
fn parse_algorithm(value: &str) -> Algorithm {
match value.to_ascii_uppercase().as_str() {
"HS384" => Algorithm::HS384,
"HS512" => Algorithm::HS512,
_ => Algorithm::HS256,
}
}
#[settings(fragment = true, section = "auth_jwt_session")]
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct JwtSessionSettings {
#[serde(default)]
pub secret: String,
#[serde(default = "default_algorithm")]
pub algorithm: String,
#[serde(default = "default_expiration")]
pub expiration: u64,
#[serde(default)]
pub issuer: Option<String>,
#[serde(default)]
pub audience: Option<String>,
}
impl Default for JwtSessionSettings {
fn default() -> Self {
Self {
secret: String::new(),
algorithm: default_algorithm(),
expiration: default_expiration(),
issuer: None,
audience: None,
}
}
}
impl JwtSessionSettings {
pub fn to_config(&self) -> JwtConfig {
JwtConfig {
secret: self.secret.clone(),
algorithm: parse_algorithm(&self.algorithm),
expiration: self.expiration,
issuer: self.issuer.clone(),
audience: self.audience.clone(),
}
}
}
impl From<&JwtSessionSettings> for JwtConfig {
fn from(settings: &JwtSessionSettings) -> Self {
settings.to_config()
}
}
pub fn create_jwt_session_backend_from_settings(
settings: &JwtSessionSettings,
) -> Result<JwtSessionBackend, JwtSessionError> {
JwtSessionBackend::new(settings.to_config())
}
}
#[cfg(feature = "jwt")]
pub use jwt_session_settings::{JwtSessionSettings, create_jwt_session_backend_from_settings};
#[cfg(feature = "token")]
mod token_rotation_settings {
use super::*;
use crate::token_rotation::{AutoTokenRotationManager, TokenRotationConfig};
use reinhardt_core::macros::settings;
fn default_rotation_interval() -> i64 {
3600 }
fn default_grace_period() -> i64 {
300 }
fn default_max_active_tokens() -> usize {
5
}
#[settings(fragment = true, section = "auth_token_rotation")]
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct TokenRotationSettings {
#[serde(default = "default_rotation_interval")]
pub rotation_interval: i64,
#[serde(default = "default_grace_period")]
pub grace_period: i64,
#[serde(default = "default_max_active_tokens")]
pub max_active_tokens: usize,
#[serde(default)]
pub rotate_on_use: bool,
}
impl Default for TokenRotationSettings {
fn default() -> Self {
Self {
rotation_interval: default_rotation_interval(),
grace_period: default_grace_period(),
max_active_tokens: default_max_active_tokens(),
rotate_on_use: false,
}
}
}
impl TokenRotationSettings {
pub fn to_config(&self) -> TokenRotationConfig {
TokenRotationConfig {
rotation_interval: self.rotation_interval,
grace_period: self.grace_period,
max_active_tokens: self.max_active_tokens,
rotate_on_use: self.rotate_on_use,
}
}
}
impl From<&TokenRotationSettings> for TokenRotationConfig {
fn from(settings: &TokenRotationSettings) -> Self {
settings.to_config()
}
}
pub fn create_token_rotation_manager_from_settings(
settings: &TokenRotationSettings,
) -> AutoTokenRotationManager {
AutoTokenRotationManager::new(settings.to_config())
}
}
#[cfg(feature = "token")]
pub use token_rotation_settings::{
TokenRotationSettings, create_token_rotation_manager_from_settings,
};
#[cfg(test)]
mod tests {
#[cfg(feature = "sessions")]
#[test]
fn session_settings_default_matches_legacy_config() {
use super::SessionSettings;
use crate::sessions::config::SessionConfig;
let from_settings = SessionSettings::default().to_config();
let legacy = SessionConfig::default();
assert_eq!(from_settings.cookie_name(), legacy.cookie_name());
assert_eq!(from_settings.cookie_age(), legacy.cookie_age());
assert_eq!(from_settings.cookie_path(), legacy.cookie_path());
assert_eq!(from_settings.cookie_domain(), legacy.cookie_domain());
assert_eq!(from_settings.cookie_secure(), legacy.cookie_secure());
assert_eq!(from_settings.cookie_httponly(), legacy.cookie_httponly());
assert_eq!(from_settings.cookie_samesite(), legacy.cookie_samesite());
assert_eq!(
from_settings.save_every_request(),
legacy.save_every_request()
);
}
#[cfg(feature = "sessions")]
#[test]
fn session_settings_round_trips_samesite_and_age() {
use super::SessionSettings;
use crate::sessions::config::SameSite;
use std::time::Duration;
let settings = SessionSettings {
cookie_samesite: "strict".to_string(),
cookie_age_secs: Some(7200),
cookie_domain: Some("example.com".to_string()),
..SessionSettings::default()
};
let config = settings.to_config();
assert_eq!(config.cookie_samesite(), SameSite::Strict);
assert_eq!(config.cookie_age(), Some(Duration::from_secs(7200)));
assert_eq!(config.cookie_domain(), Some("example.com"));
}
#[cfg(feature = "jwt")]
#[test]
fn jwt_session_settings_default_matches_legacy_config() {
use super::JwtSessionSettings;
use crate::sessions::backends::jwt::JwtConfig;
use jsonwebtoken::Algorithm;
let settings = JwtSessionSettings::default();
let config = settings.to_config();
let legacy = JwtConfig::new(String::new());
assert_eq!(config.secret, settings.secret);
assert_eq!(config.algorithm, Algorithm::HS256);
assert_eq!(config.algorithm, legacy.algorithm);
assert_eq!(config.expiration, legacy.expiration);
assert_eq!(config.issuer, legacy.issuer);
assert_eq!(config.audience, legacy.audience);
}
#[cfg(feature = "token")]
#[test]
fn token_rotation_settings_default_matches_legacy_config() {
use super::TokenRotationSettings;
use crate::token_rotation::TokenRotationConfig;
let from_settings = TokenRotationSettings::default().to_config();
let legacy = TokenRotationConfig::default();
assert_eq!(from_settings.rotation_interval, legacy.rotation_interval);
assert_eq!(from_settings.grace_period, legacy.grace_period);
assert_eq!(from_settings.max_active_tokens, legacy.max_active_tokens);
assert_eq!(from_settings.rotate_on_use, legacy.rotate_on_use);
}
}