use blvm_node::rpc::auth::{RpcAuthManager, UserId};
use hyper::HeaderMap;
use std::net::SocketAddr;
#[tokio::test]
async fn test_auth_bypass_attempt_empty_token() {
let manager = RpcAuthManager::new(true);
let addr: SocketAddr = "127.0.0.1:8080".parse().unwrap();
let headers = HeaderMap::new();
let result = manager.authenticate_request(&headers, addr).await;
assert!(result.user_id.is_none());
assert!(result.requires_auth);
assert!(result.error.is_some());
}
#[tokio::test]
async fn test_auth_bypass_attempt_malformed_token() {
let manager = RpcAuthManager::new(true);
let addr: SocketAddr = "127.0.0.1:8080".parse().unwrap();
let mut headers = HeaderMap::new();
headers.insert("authorization", "InvalidFormat token".parse().unwrap());
let result = manager.authenticate_request(&headers, addr).await;
assert!(result.user_id.is_none());
assert!(result.requires_auth);
}
#[tokio::test]
async fn test_auth_bypass_attempt_invalid_token() {
let manager = RpcAuthManager::new(true);
let addr: SocketAddr = "127.0.0.1:8080".parse().unwrap();
let mut headers = HeaderMap::new();
headers.insert("authorization", "Bearer invalid-token-123".parse().unwrap());
let result = manager.authenticate_request(&headers, addr).await;
assert!(result.user_id.is_none());
assert!(result.requires_auth);
assert!(result.error.is_some());
}
#[tokio::test]
async fn test_auth_valid_token_accepted() {
let manager = RpcAuthManager::new(true);
let token_str = "valid-token".to_string();
manager.add_token(token_str.clone()).await.unwrap();
let addr: SocketAddr = "127.0.0.1:8080".parse().unwrap();
let mut headers = HeaderMap::new();
headers.insert(
"authorization",
format!("Bearer {token_str}").parse().unwrap(),
);
let result = manager.authenticate_request(&headers, addr).await;
assert!(result.user_id.is_some());
match result.user_id {
Some(UserId::Token(_)) => {} _ => panic!("Expected Token variant"),
}
assert!(result.error.is_none());
}
#[tokio::test]
async fn test_auth_no_auth_required_allows_access() {
let manager = RpcAuthManager::new(false);
let addr: SocketAddr = "127.0.0.1:8080".parse().unwrap();
let headers = HeaderMap::new();
let result = manager.authenticate_request(&headers, addr).await;
assert!(!result.requires_auth);
match result.user_id {
Some(UserId::Ip(ip)) => assert_eq!(ip, addr),
_ => panic!("Expected IP-based user_id when auth not required"),
}
}
#[tokio::test]
async fn test_auth_token_revocation() {
let manager = RpcAuthManager::new(true);
let token_str = "revocable-token".to_string();
manager.add_token(token_str.clone()).await.unwrap();
let addr: SocketAddr = "127.0.0.1:8080".parse().unwrap();
let mut headers = HeaderMap::new();
headers.insert(
"authorization",
format!("Bearer {token_str}").parse().unwrap(),
);
let result = manager.authenticate_request(&headers, addr).await;
assert!(result.user_id.is_some());
manager.remove_token(&token_str).await.unwrap();
let result = manager.authenticate_request(&headers, addr).await;
assert!(result.user_id.is_none());
assert!(result.error.is_some());
}
#[tokio::test]
async fn test_auth_concurrent_requests() {
use std::sync::Arc;
let manager = Arc::new(RpcAuthManager::new(true));
let token_str = "concurrent-token".to_string();
manager.add_token(token_str.clone()).await.unwrap();
let addr: SocketAddr = "127.0.0.1:8080".parse().unwrap();
let mut headers = HeaderMap::new();
headers.insert(
"authorization",
format!("Bearer {token_str}").parse().unwrap(),
);
let mut handles = vec![];
for _ in 0..10 {
let manager_clone = Arc::clone(&manager);
let headers_clone = headers.clone();
let addr_clone = addr;
handles.push(tokio::spawn(async move {
manager_clone
.authenticate_request(&headers_clone, addr_clone)
.await
}));
}
for handle in handles {
let result = handle.await.unwrap();
assert!(result.user_id.is_some());
}
}
#[tokio::test]
async fn test_auth_brute_force_protection() {
let manager = RpcAuthManager::new(true);
let addr: SocketAddr = "127.0.0.1:8080".parse().unwrap();
for i in 0..100 {
let mut headers = HeaderMap::new();
headers.insert(
"authorization",
format!("Bearer invalid-token-{i}").parse().unwrap(),
);
let result = manager.authenticate_request(&headers, addr).await;
assert!(result.user_id.is_none());
assert!(result.error.is_some());
}
}
#[tokio::test]
async fn test_rpc_rate_limiting_without_auth() {
let manager = RpcAuthManager::with_rate_limits(false, 5, 1);
let addr: SocketAddr = "127.0.0.1:9999".parse().unwrap();
for _ in 0..5 {
assert!(
manager
.check_ip_rate_limit_with_endpoint(addr, Some("rpc:getblockchaininfo"))
.await,
"Burst requests should be allowed"
);
}
assert!(
!manager
.check_ip_rate_limit_with_endpoint(addr, Some("rpc:getblockchaininfo"))
.await,
"Request beyond burst should be rate limited"
);
}
#[tokio::test]
async fn test_batch_rate_limiting() {
let manager = RpcAuthManager::with_rate_limits(false, 5, 1);
let addr: SocketAddr = "127.0.0.1:8888".parse().unwrap();
assert!(
!manager
.check_ip_rate_limit_with_endpoint_n(addr, Some("rpc:batch"), 10)
.await,
"Batch exceeding burst should be rate limited"
);
assert!(
manager
.check_ip_rate_limit_with_endpoint(addr, Some("rpc:getblockchaininfo"))
.await,
"Single request after failed batch should still work"
);
}
#[tokio::test]
async fn test_auth_case_sensitive_token() {
let manager = RpcAuthManager::new(true);
let token_str = "CaseSensitiveToken".to_string();
manager.add_token(token_str.clone()).await.unwrap();
let addr: SocketAddr = "127.0.0.1:8080".parse().unwrap();
let mut headers = HeaderMap::new();
headers.insert(
"authorization",
format!("Bearer {token_str}").parse().unwrap(),
);
let result = manager.authenticate_request(&headers, addr).await;
assert!(result.user_id.is_some());
let mut headers2 = HeaderMap::new();
headers2.insert(
"authorization",
"Bearer casesensitivetoken".parse().unwrap(),
);
let result = manager.authenticate_request(&headers2, addr).await;
assert!(result.user_id.is_none());
}