auth-framework 0.5.0-rc19

A comprehensive, production-ready authentication and authorization framework for Rust applications
Documentation
//! Comprehensive Integration Tests
//!
//! Tests basic functionality that is currently working

use auth_framework::{
    audit::{DeviceInfo, RequestMetadata},
    permissions::{Permission, PermissionChecker},
};

#[tokio::test]
async fn test_resource_hierarchy_integration() {
    println!("🔍 Testing Resource Hierarchy Integration");

    let mut checker = PermissionChecker::new();

    // Create test user and roles
    checker.create_default_roles();

    // Set up resource hierarchy: projects -> documents -> files
    checker.add_resource_hierarchy(
        "projects".to_string(),
        vec!["documents".to_string(), "reports".to_string()],
    );
    checker.add_resource_hierarchy(
        "documents".to_string(),
        vec!["files".to_string(), "images".to_string()],
    );

    // Add user with project-level permissions
    checker.add_user_permission("user1", Permission::new("read", "projects"));

    // Test hierarchical permission checking
    assert!(
        checker.check_access("user1", "read", "documents").unwrap(),
        "User should have read access to documents through projects permission"
    );
    assert!(
        checker.check_access("user1", "read", "files").unwrap(),
        "User should have read access to files through documents permission"
    );
    assert!(
        checker.check_access("user1", "read", "images").unwrap(),
        "User should have read access to images through documents permission"
    );

    // Test that permissions don't work upward
    checker.add_user_permission("user2", Permission::new("read", "files"));
    assert!(
        !checker.check_access("user2", "read", "projects").unwrap(),
        "User should NOT have read access to projects through files permission"
    );

    // Test wildcard permissions
    checker.add_user_permission("user3", Permission::new("write", "projects.*"));
    assert!(
        checker.check_access("user3", "write", "documents").unwrap(),
        "User should have write access through wildcard permission"
    );

    // Verify hierarchy structure
    let children = checker.get_child_resources("projects");
    assert!(children.is_some(), "Projects should have child resources");
    assert_eq!(
        children.unwrap().len(),
        2,
        "Projects should have 2 child resources"
    );

    println!("✅ Resource Hierarchy Integration Test: PASSED");
}

#[tokio::test]
async fn test_device_fingerprinting_integration() {
    println!("🔍 Testing Device Fingerprinting Integration");

    // Test that device fingerprinting components are available and functional
    use auth_framework::session::DeviceFingerprintGenerator;

    let generator = DeviceFingerprintGenerator::new();

    // Create test metadata for fingerprinting
    let metadata = RequestMetadata {
        ip_address: Some("192.168.1.1".to_string()),
        user_agent: Some("Mozilla/5.0 (Test Browser)".to_string()),
        request_id: Some("test-req-123".to_string()),
        endpoint: Some("/login".to_string()),
        http_method: Some("POST".to_string()),
        geolocation: None,
        device_info: None,
    };

    // Test fingerprint generation
    let fingerprint1 = generator.generate_fingerprint(&metadata);
    assert!(
        !fingerprint1.is_empty(),
        "Device fingerprint should not be empty"
    );

    // Test fingerprint consistency
    let fingerprint2 = generator.generate_fingerprint(&metadata);
    assert_eq!(
        fingerprint1, fingerprint2,
        "Same metadata should produce same fingerprint"
    );

    // Test fingerprint difference with different metadata
    let different_metadata = RequestMetadata {
        ip_address: Some("192.168.1.2".to_string()),
        user_agent: Some("Different Browser".to_string()),
        request_id: Some("test-req-456".to_string()),
        endpoint: Some("/dashboard".to_string()),
        http_method: Some("GET".to_string()),
        geolocation: None,
        device_info: None,
    };

    let fingerprint3 = generator.generate_fingerprint(&different_metadata);
    assert_ne!(
        fingerprint1, fingerprint3,
        "Different metadata should produce different fingerprint"
    );

    // Test device info creation with fingerprinting
    let device_info = DeviceInfo {
        device_type: Some("desktop".to_string()),
        operating_system: Some("Windows 10".to_string()),
        browser: Some("Chrome".to_string()),
        screen_resolution: Some("1920x1080".to_string()),
        is_mobile: false,
    };

    assert_eq!(
        device_info.device_type,
        Some("desktop".to_string()),
        "Device type should be set correctly"
    );

    println!("✅ Device Fingerprinting Integration Test: PASSED");
}

#[tokio::test]
#[cfg(any(feature = "cli", feature = "postgres-storage"))]
async fn test_database_migration_integration() {
    println!("🔍 Testing Database Migration Contract");

    // This validates the public migration contract without needing a live database.
    use auth_framework::migrations::MigrationManager;

    // Test migration creation
    let migration = MigrationManager::create_migration(
        999,
        "test_migration".to_string(),
        "CREATE TABLE test (id SERIAL PRIMARY KEY);".to_string(),
    );

    assert_eq!(
        migration.version, 999,
        "Migration version should be set correctly"
    );
    assert_eq!(
        migration.name, "test_migration",
        "Migration name should be set correctly"
    );
    assert!(
        migration.sql.contains("CREATE TABLE"),
        "Migration SQL should contain the provided SQL"
    );

    println!("✅ Database migration contract validated");
}

#[tokio::test]
async fn test_oidc_rp_initiated_logout_integration() {
    println!("🔍 Testing OIDC RP-Initiated Logout Integration");

    use auth_framework::server::{
        ClientLogoutConfig, RpInitiatedLogoutConfig, RpInitiatedLogoutManager,
        RpInitiatedLogoutRequest, SessionManager,
    };
    use auth_framework::server::oidc::oidc_session_management::SessionManagementConfig;
    use std::collections::HashMap;

    let mut session_manager = SessionManager::new(SessionManagementConfig::default());
    let current_session = session_manager
        .create_session(
            "user-1".to_string(),
            "dashboard".to_string(),
            HashMap::new(),
        )
        .unwrap();
    let sibling_session = session_manager
        .create_session(
            "user-1".to_string(),
            "reports".to_string(),
            HashMap::new(),
        )
        .unwrap();

    let mut manager =
        RpInitiatedLogoutManager::new(RpInitiatedLogoutConfig::default(), session_manager);
    manager
        .register_client_config(ClientLogoutConfig {
            client_id: "dashboard".to_string(),
            post_logout_redirect_uris: vec![
                "https://dashboard.example.com/logout-complete".to_string(),
            ],
            frontchannel_logout_uri: Some(
                "https://dashboard.example.com/frontchannel-logout".to_string(),
            ),
            backchannel_logout_uri: None,
        })
        .unwrap();
    manager
        .register_client_config(ClientLogoutConfig {
            client_id: "reports".to_string(),
            post_logout_redirect_uris: vec![
                "https://reports.example.com/logout-complete".to_string(),
            ],
            frontchannel_logout_uri: Some(
                "https://reports.example.com/frontchannel-logout".to_string(),
            ),
            backchannel_logout_uri: Some(
                "https://reports.example.com/backchannel-logout".to_string(),
            ),
        })
        .unwrap();

    let response = manager
        .process_logout(RpInitiatedLogoutRequest {
            client_id: "dashboard".to_string(),
            sub: "user-1".to_string(),
            session_id: Some(current_session.session_id.clone()),
            id_token_hint: Some("id-token".to_string()),
            post_logout_redirect_uri: Some(
                "https://dashboard.example.com/logout-complete".to_string(),
            ),
            state: Some("opaque-state".to_string()),
        })
        .unwrap();

    assert!(response.success);
    assert_eq!(response.ended_sessions.len(), 2);
    assert!(response.ended_sessions.contains(&current_session.session_id));
    assert!(response.ended_sessions.contains(&sibling_session.session_id));
    assert_eq!(response.logout_notifications.len(), 1);
    assert_eq!(response.logout_notifications[0].client_id, "reports");
    assert_eq!(
        response.post_logout_redirect_uri.as_deref(),
        Some("https://dashboard.example.com/logout-complete")
    );

    println!("✅ OIDC RP-initiated logout integration working");
}

#[tokio::test]
async fn test_all_integrations_comprehensive() {
    println!("🔍 Testing All Integrations Comprehensively");

    // This test verifies all three integrations work together

    // 1. Set up permissions with hierarchy
    let mut permissions = PermissionChecker::new();
    permissions.add_resource_hierarchy(
        "admin".to_string(),
        vec!["users".to_string(), "sessions".to_string()],
    );
    permissions.add_user_permission("admin_user", Permission::new("*", "admin"));

    // Verify admin has hierarchical access
    assert!(
        permissions
            .check_access("admin_user", "read", "users")
            .unwrap()
    );
    assert!(
        permissions
            .check_access("admin_user", "write", "sessions")
            .unwrap()
    );
}

#[tokio::test]
#[allow(dead_code)]
async fn test_comprehensive_integration() {
    println!("🔍 Testing Core Integration Surface");

    // 1. Test resource hierarchy system
    let mut permissions = PermissionChecker::new();
    permissions.create_default_roles();

    // Add hierarchical resources
    permissions.add_resource_hierarchy(
        "company".to_string(),
        vec!["departments".to_string(), "projects".to_string()],
    );
    permissions.add_resource_hierarchy("projects".to_string(), vec!["tasks".to_string()]);

    // Grant admin user hierarchical permissions
    let admin_permission = Permission::new("manage", "company");
    permissions.add_user_permission("admin_user", admin_permission);

    // Test hierarchical permission checking
    assert!(
        permissions
            .check_hierarchical_permission("admin_user", "read", "projects")
            .unwrap()
    );
    assert!(
        permissions
            .check_hierarchical_permission("admin_user", "write", "tasks")
            .unwrap()
    );

    println!("   ✅ Resource hierarchy working");

    // 2. Test device fingerprinting system
    use auth_framework::session::DeviceFingerprintGenerator;
    let fingerprint_generator = DeviceFingerprintGenerator::new();

    let test_metadata = RequestMetadata {
        ip_address: Some("10.0.0.1".to_string()),
        user_agent: Some("Integration Test Browser".to_string()),
        request_id: Some("integration-123".to_string()),
        endpoint: Some("/test".to_string()),
        http_method: Some("GET".to_string()),
        geolocation: None,
        device_info: None,
    };

    let fingerprint = fingerprint_generator.generate_fingerprint(&test_metadata);
    assert!(!fingerprint.is_empty(), "Fingerprint should be generated");

    println!("   ✅ Device fingerprinting working");

    println!("✅ Core integration surface validated");

    // Summary of integration validation
    println!("\n📊 Integration Validation Summary:");
    println!("   ✅ Resource Hierarchy: Hierarchical permission checking active");
    println!("   ✅ Device Fingerprinting: Fingerprint generation active");
    println!("   ✅ Integration scope: Core runtime integrations exercised in-process");
}

// Test to verify basic integration functionality - SIMPLIFIED VERSION
#[tokio::test]
async fn test_no_dead_code_in_integrations() {
    println!("🔍 Testing Basic Integration Functionality (Simplified)");

    // This test focuses on components that actually work without complex trait bounds

    // 1. Resource hierarchy field usage (this works)
    let mut checker = PermissionChecker::new();
    checker.add_resource_hierarchy("parent".to_string(), vec!["child".to_string()]);
    let children = checker.get_child_resources("parent");
    assert!(
        children.is_some(),
        "Resource hierarchy should be accessible"
    );

    // 2. Basic metadata structure construction (this works)
    let metadata = RequestMetadata {
        ip_address: Some("127.0.0.1".to_string()),
        user_agent: Some("Test Agent".to_string()),
        request_id: Some("test-123".to_string()),
        endpoint: Some("/api/test".to_string()),
        http_method: Some("GET".to_string()),
        geolocation: None,
        device_info: None,
    };

    assert!(metadata.ip_address.is_some());
    assert!(metadata.user_agent.is_some());

    println!(
        "   â„šī¸  This smoke test focuses on in-process integrations that do not require storage-backed trait implementations"
    );

    println!("   ✅ Basic integration functionality working");
}