#[cfg(test)]
mod edge_cases {
use super::super::session::*;
use super::super::test_utils::*;
use crate::SESSION_COOKIE_NAME;
use crate::session::errors::SessionError;
use crate::session::types::{SessionId, StoredSession, UserId};
use crate::storage::{CacheData, CacheKey, CachePrefix, GENERIC_CACHE_STORE};
use crate::test_utils::init_test_environment;
use chrono::{Duration, Utc};
use http::{HeaderMap, Method};
use serial_test::serial;
#[tokio::test]
async fn test_expired_session_direct() {
init_test_environment().await;
let session_id = "test_expired_session_direct";
let user_id = "test_user_expired_direct";
let csrf_token = "csrf_token_expired";
let expires_at = Utc::now() - Duration::hours(1);
let stored_session = StoredSession {
user_id: user_id.to_string(),
csrf_token: csrf_token.to_string(),
expires_at,
ttl: 3600,
};
let cache_data = CacheData {
value: serde_json::to_string(&stored_session).unwrap(),
};
let cache_prefix = CachePrefix::new("session".to_string()).unwrap();
let cache_key = CacheKey::new(session_id.to_string()).unwrap();
GENERIC_CACHE_STORE
.lock()
.await
.put(cache_prefix, cache_key, cache_data)
.await
.unwrap();
let session_cookie = crate::SessionCookie::new(session_id.to_string()).unwrap();
let result = get_csrf_token_from_session(&session_cookie).await;
assert!(result.is_err());
match result {
Err(SessionError::SessionExpiredError) => {} other => panic!("Expected SessionError::SessionExpiredError, got: {other:?}"),
}
let cache_prefix = CachePrefix::new("session".to_string()).unwrap();
let cache_key = CacheKey::new(session_id.to_string()).unwrap();
let check_session = GENERIC_CACHE_STORE
.lock()
.await
.get(cache_prefix, cache_key)
.await
.unwrap();
assert!(check_session.is_none());
}
#[tokio::test]
async fn test_malformed_session_data() {
init_test_environment().await;
let session_id = "malformed_session_data";
let cache_data = CacheData {
value: r#"{"user_id": "invalid_json"#.to_string(), };
let cache_prefix = CachePrefix::new("session".to_string()).unwrap();
let cache_key = CacheKey::new(session_id.to_string()).unwrap();
GENERIC_CACHE_STORE
.lock()
.await
.put(cache_prefix, cache_key, cache_data)
.await
.unwrap();
let session_cookie = crate::SessionCookie::new(session_id.to_string()).unwrap();
let result = get_csrf_token_from_session(&session_cookie).await;
assert!(result.is_err());
match result {
Err(SessionError::Storage(_)) => {} other => panic!("Expected SessionError::Storage, got: {other:?}"),
}
let _ =
delete_test_session(SessionId::new(session_id.to_string()).expect("Valid session ID"))
.await;
}
#[tokio::test]
async fn test_missing_fields_in_session() {
init_test_environment().await;
let session_id = "missing_fields_session";
let incomplete_json = r#"{"user_id": "test_user"}"#; let cache_data = CacheData {
value: incomplete_json.to_string(),
};
let cache_prefix = CachePrefix::new("session".to_string()).unwrap();
let cache_key = CacheKey::new(session_id.to_string()).unwrap();
GENERIC_CACHE_STORE
.lock()
.await
.put(cache_prefix, cache_key, cache_data)
.await
.unwrap();
let session_cookie = crate::SessionCookie::new(session_id.to_string()).unwrap();
let result = get_csrf_token_from_session(&session_cookie).await;
assert!(result.is_err());
match result {
Err(SessionError::Storage(_)) => {} other => panic!("Expected SessionError::Storage, got: {other:?}"),
}
let _ =
delete_test_session(SessionId::new(session_id.to_string()).expect("Valid session ID"))
.await;
}
#[tokio::test]
async fn test_is_authenticated_post_missing_csrf_token() {
init_test_environment().await;
let user_id = "user_missing_csrf";
let csrf_token = "csrf_token_123";
let session_id = "session_missing_csrf";
let _ = create_test_user_and_session(
UserId::new(user_id.to_string()).expect("Valid user ID"),
"missing_csrf@example.com",
"Missing CSRF",
false,
SessionId::new(session_id.to_string()).expect("Valid session ID"),
csrf_token,
3600,
)
.await;
let cookie_name = SESSION_COOKIE_NAME.to_string();
let mut headers = HeaderMap::new();
headers.insert(
http::header::COOKIE,
format!("{}={}", &cookie_name, session_id).parse().unwrap(),
);
let result = is_authenticated_basic_then_csrf(&headers, &Method::POST).await;
assert!(result.is_err());
match result {
Err(SessionError::CsrfToken(_)) => {} other => panic!("Expected SessionError::CsrfToken, got: {other:?}"),
}
let _ = cleanup_test_resources(
UserId::new(user_id.to_string()).expect("Valid user ID"),
SessionId::new(session_id.to_string()).expect("Valid session ID"),
)
.await;
}
#[tokio::test]
#[serial]
async fn test_is_authenticated_strict_then_csrf() {
init_test_environment().await;
let user_id = "user_strict_csrf_test";
let csrf_token = "csrf_strict_token";
let session_id = "session_strict_csrf";
let _ = create_test_user_and_session(
UserId::new(user_id.to_string()).expect("Valid user ID"),
"strict_csrf@example.com",
"Strict CSRF Test",
false,
SessionId::new(session_id.to_string()).expect("Valid session ID"),
csrf_token,
3600,
)
.await;
let cookie_name = SESSION_COOKIE_NAME.to_string();
let mut headers = HeaderMap::new();
headers.insert(
http::header::COOKIE,
format!("{}={}", &cookie_name, session_id).parse().unwrap(),
);
headers.insert("X-CSRF-Token", csrf_token.parse().unwrap());
let result = is_authenticated_strict_then_csrf(&headers, &Method::POST).await;
assert!(result.is_ok());
let (csrf_token_result, csrf_header_verified) = result.unwrap();
assert_eq!(csrf_token_result.as_str(), csrf_token);
assert!(csrf_header_verified.0);
let mut headers_invalid_csrf = HeaderMap::new();
headers_invalid_csrf.insert(
http::header::COOKIE,
format!("{}={}", &cookie_name, session_id).parse().unwrap(),
);
headers_invalid_csrf.insert("X-CSRF-Token", "wrong_token".parse().unwrap());
let result = is_authenticated_strict_then_csrf(&headers_invalid_csrf, &Method::POST).await;
assert!(result.is_err());
match result {
Err(SessionError::CsrfToken(_)) => {} other => panic!("Expected SessionError::CsrfToken, got: {other:?}"),
}
let _ = cleanup_test_resources(
UserId::new(user_id.to_string()).expect("Valid user ID"),
SessionId::new(session_id.to_string()).expect("Valid session ID"),
)
.await;
}
#[tokio::test]
#[serial]
async fn test_is_authenticated_basic_then_user_and_csrf() {
init_test_environment().await;
let user_id = "basic_user_and_csrf";
let account = "basic_csrf@example.com";
let label = "Basic User and CSRF";
let csrf_token = "basic_user_csrf_token";
let session_id = "basic_user_csrf_session";
let _ = create_test_user_and_session(
UserId::new(user_id.to_string()).expect("Valid user ID"),
account,
label,
false,
SessionId::new(session_id.to_string()).expect("Valid session ID"),
csrf_token,
3600,
)
.await;
let cookie_name = SESSION_COOKIE_NAME.to_string();
let mut headers = HeaderMap::new();
headers.insert(
http::header::COOKIE,
format!("{}={}", &cookie_name, session_id).parse().unwrap(),
);
headers.insert("X-CSRF-Token", csrf_token.parse().unwrap());
let result = is_authenticated_basic_then_user_and_csrf(&headers, &Method::POST).await;
assert!(result.is_ok());
let (user, csrf_token_result, csrf_header_verified) = result.unwrap();
assert_eq!(user.id, user_id);
assert_eq!(user.account, account);
assert_eq!(user.label, label);
assert_eq!(csrf_token_result.as_str(), csrf_token);
assert!(csrf_header_verified.0);
let _ = cleanup_test_resources(
UserId::new(user_id.to_string()).expect("Valid user ID"),
SessionId::new(session_id.to_string()).expect("Valid session ID"),
)
.await;
}
}