Private
Public Access
1
0
Files
linux_patch_api/tests/integration/auth_test.rs
Draco-Lunaris-Echo eac05ad1eb
Some checks failed
CI/CD Pipeline / Code Format (push) Successful in 4s
CI/CD Pipeline / Clippy Lints (push) Successful in 44s
CI/CD Pipeline / All Unit Tests (push) Successful in 1m24s
CI/CD Pipeline / Security Audit (push) Successful in 4s
CI/CD Pipeline / Enrollment Tests (push) Successful in 1m15s
CI/CD Pipeline / Verify Enrollment CLI Flag (push) Successful in 1m0s
CI/CD Pipeline / Build Debian Package (push) Failing after 4s
CI/CD Pipeline / Build Debian Package (Ubuntu 22.04) (push) Failing after 4s
CI/CD Pipeline / Build RPM Package (push) Successful in 2m17s
CI/CD Pipeline / Build Arch Package (push) Successful in 2m25s
CI/CD Pipeline / Build Alpine Package (push) Failing after 3m15s
fix: remove dead min_tls_version config field, TLS 1.3 is only supported version (closes #16)
Co-authored-by: git-echo <git-echo@moon-dragon.us>
2026-06-06 16:50:55 -05:00

297 lines
9.3 KiB
Rust

//! Integration Tests for Authentication Layer
//!
//! Tests mTLS authentication and IP whitelist enforcement.
use linux_patch_api::auth::{mtls, whitelist, AuthResult};
use std::net::Ipv4Addr;
#[cfg(test)]
mod mtls_tests {
use super::*;
#[test]
fn test_mtls_config_creation() {
let config = mtls::MtlsConfig {
ca_cert_path: "/etc/linux_patch_api/certs/ca.pem".to_string(),
server_cert_path: "/etc/linux_patch_api/certs/server.pem".to_string(),
server_key_path: "/etc/linux_patch_api/certs/server.key".to_string(),
};
assert_eq!(config.ca_cert_path, "/etc/linux_patch_api/certs/ca.pem");
assert_eq!(
config.server_cert_path,
"/etc/linux_patch_api/certs/server.pem"
);
assert_eq!(
config.server_key_path,
"/etc/linux_patch_api/certs/server.key"
);
}
#[test]
fn test_mtls_error_types() {
// Test that error types can be created
let io_error = mtls::MtlsError::IoError("test".to_string());
assert!(io_error.to_string().contains("test"));
let parse_error = mtls::MtlsError::ParseError("test".to_string());
assert!(parse_error.to_string().contains("test"));
let validation_error = mtls::MtlsError::ValidationError("test".to_string());
assert!(validation_error.to_string().contains("test"));
}
#[test]
fn test_client_cert_info() {
let info = mtls::ClientCertInfo {
subject: "CN=client001,O=Internal,C=US".to_string(),
issuer: "CN=Linux Patch API CA,O=Internal,C=US".to_string(),
serial: "01".to_string(),
not_before: chrono::Utc::now(),
not_after: chrono::Utc::now() + chrono::Duration::days(365),
};
assert!(info.subject.contains("CN=client001"));
assert!(info.issuer.contains("Linux Patch API CA"));
assert_eq!(info.serial, "01");
}
}
#[cfg(test)]
mod whitelist_tests {
use super::*;
use std::fs;
use tempfile::TempDir;
fn create_test_whitelist(content: &str) -> (TempDir, String) {
let temp_dir = TempDir::new().unwrap();
let whitelist_path = temp_dir.path().join("whitelist.yaml");
fs::write(&whitelist_path, content).unwrap();
(temp_dir, whitelist_path.to_string_lossy().to_string())
}
#[test]
fn test_whitelist_single_ip() {
let (_temp_dir, whitelist_path) = create_test_whitelist(
r#"entries:
- "192.168.1.100"
"#,
);
let manager = whitelist::WhitelistManager::new(&whitelist_path).unwrap();
let allowed_ip: Ipv4Addr = "192.168.1.100".parse().unwrap();
assert!(manager.is_allowed(&allowed_ip));
let denied_ip: Ipv4Addr = "192.168.1.101".parse().unwrap();
assert!(!manager.is_allowed(&denied_ip));
}
#[test]
fn test_whitelist_cidr_subnet() {
let (_temp_dir, whitelist_path) = create_test_whitelist(
r#"entries:
- "192.168.1.0/24"
"#,
);
let manager = whitelist::WhitelistManager::new(&whitelist_path).unwrap();
// IPs within subnet should be allowed
assert!(manager.is_allowed(&"192.168.1.1".parse().unwrap()));
assert!(manager.is_allowed(&"192.168.1.100".parse().unwrap()));
assert!(manager.is_allowed(&"192.168.1.254".parse().unwrap()));
// IPs outside subnet should be denied
assert!(!manager.is_allowed(&"192.168.2.1".parse().unwrap()));
assert!(!manager.is_allowed(&"192.167.1.1".parse().unwrap()));
}
#[test]
fn test_whelist_multiple_entries() {
let (_temp_dir, whitelist_path) = create_test_whitelist(
r#"entries:
- "192.168.1.0/24"
- "10.0.0.50"
- "172.16.0.0/16"
"#,
);
let manager = whitelist::WhitelistManager::new(&whitelist_path).unwrap();
// All these should be allowed
assert!(manager.is_allowed(&"192.168.1.100".parse().unwrap()));
assert!(manager.is_allowed(&"10.0.0.50".parse().unwrap()));
assert!(manager.is_allowed(&"172.16.50.100".parse().unwrap()));
// These should be denied
assert!(!manager.is_allowed(&"192.168.2.100".parse().unwrap()));
assert!(!manager.is_allowed(&"10.0.0.51".parse().unwrap()));
assert!(!manager.is_allowed(&"172.17.0.1".parse().unwrap()));
}
#[test]
fn test_whitelist_entry_count() {
let (_temp_dir, whitelist_path) = create_test_whitelist(
r#"entries:
- "192.168.1.0/24"
- "10.0.0.50"
"#,
);
let manager = whitelist::WhitelistManager::new(&whitelist_path).unwrap();
assert_eq!(manager.entry_count(), 2);
}
#[test]
fn test_whitelist_socket_addr() {
use std::net::SocketAddr;
let (_temp_dir, whitelist_path) = create_test_whitelist(
r#"entries:
- "192.168.1.0/24"
"#,
);
let manager = whitelist::WhitelistManager::new(&whitelist_path).unwrap();
let allowed_socket: SocketAddr = "192.168.1.100:8080".parse().unwrap();
assert!(manager.is_socket_allowed(&allowed_socket));
let denied_socket: SocketAddr = "192.168.2.100:8080".parse().unwrap();
assert!(!manager.is_socket_allowed(&denied_socket));
}
}
#[cfg(test)]
mod auth_result_tests {
use super::*;
#[test]
fn test_auth_result_fully_authenticated() {
let result = AuthResult {
mtls_valid: true,
ip_allowed: true,
cert_info: None,
client_ip: Some("192.168.1.100".parse().unwrap()),
};
assert!(result.is_authenticated());
assert!(result.mtls_valid);
assert!(result.ip_allowed);
}
#[test]
fn test_auth_result_mtls_failed() {
let result = AuthResult {
mtls_valid: false,
ip_allowed: true,
cert_info: None,
client_ip: Some("192.168.1.100".parse().unwrap()),
};
assert!(!result.is_authenticated());
}
#[test]
fn test_auth_result_ip_denied() {
let result = AuthResult {
mtls_valid: true,
ip_allowed: false,
cert_info: None,
client_ip: Some("192.168.1.100".parse().unwrap()),
};
assert!(!result.is_authenticated());
}
#[test]
fn test_auth_result_both_failed() {
let result = AuthResult {
mtls_valid: false,
ip_allowed: false,
cert_info: None,
client_ip: Some("192.168.1.100".parse().unwrap()),
};
assert!(!result.is_authenticated());
}
#[test]
fn test_auth_result_with_cert_info() {
let cert_info = mtls::ClientCertInfo {
subject: "CN=client001".to_string(),
issuer: "CN=Linux Patch API CA".to_string(),
serial: "01".to_string(),
not_before: chrono::Utc::now(),
not_after: chrono::Utc::now() + chrono::Duration::days(365),
};
let result = AuthResult {
mtls_valid: true,
ip_allowed: true,
cert_info: Some(cert_info),
client_ip: Some("192.168.1.100".parse().unwrap()),
};
assert!(result.is_authenticated());
assert!(result.cert_info.is_some());
assert_eq!(result.cert_info.unwrap().subject, "CN=client001");
}
}
/// Integration tests for SecurityHeadersMiddleware (VULN-006)
#[cfg(test)]
mod security_headers_tests {
use actix_web::http::header;
use linux_patch_api::auth::security_headers::has_duplicate_critical_headers;
#[test]
fn test_no_duplicate_headers_passes() {
let mut headers = header::HeaderMap::new();
headers.insert(header::CONTENT_TYPE, "application/json".parse().unwrap());
headers.insert(header::AUTHORIZATION, "Bearer test".parse().unwrap());
headers.insert(header::HOST, "localhost".parse().unwrap());
assert!(!has_duplicate_critical_headers(&headers));
}
#[test]
fn test_duplicate_content_type_detected() {
let mut headers = header::HeaderMap::new();
headers.insert(header::CONTENT_TYPE, "application/json".parse().unwrap());
headers.append(header::CONTENT_TYPE, "text/plain".parse().unwrap());
assert!(has_duplicate_critical_headers(&headers));
}
#[test]
fn test_duplicate_authorization_detected() {
let mut headers = header::HeaderMap::new();
headers.insert(header::AUTHORIZATION, "Bearer test1".parse().unwrap());
headers.append(header::AUTHORIZATION, "Bearer test2".parse().unwrap());
assert!(has_duplicate_critical_headers(&headers));
}
#[test]
fn test_duplicate_host_detected() {
let mut headers = header::HeaderMap::new();
headers.insert(header::HOST, "localhost".parse().unwrap());
headers.append(header::HOST, "evil.com".parse().unwrap());
assert!(has_duplicate_critical_headers(&headers));
}
#[test]
fn test_non_critical_duplicates_allowed() {
// Duplicate Accept headers should be fine
let mut headers = header::HeaderMap::new();
headers.insert(header::ACCEPT, "text/html".parse().unwrap());
headers.append(header::ACCEPT, "application/json".parse().unwrap());
assert!(!has_duplicate_critical_headers(&headers));
}
#[test]
fn test_empty_headers_passes() {
let headers = header::HeaderMap::new();
assert!(!has_duplicate_critical_headers(&headers));
}
}