validate_access/
validate_access.rs

1use nacm_validator::{AccessRequest, NacmConfig, Operation, RuleEffect, RequestContext};
2use std::path::Path;
3
4fn main() -> Result<(), Box<dyn std::error::Error>> {
5    // Load the NACM configuration from the XML file
6    // Use a more robust path resolution
7    let xml_path = Path::new(env!("CARGO_MANIFEST_DIR"))
8        .join("examples")
9        .join("data")
10        .join("aaa_ncm_init.xml");
11    
12    let xml_content = std::fs::read_to_string(&xml_path)
13        .map_err(|e| format!("Failed to read XML file at {:?}: {}", xml_path, e))?;
14    
15    let config = NacmConfig::from_xml(&xml_content)?;
16    
17    println!("NACM Configuration loaded:");
18    println!("- NACM enabled: {}", config.enable_nacm);
19    println!("- Default policies: read={:?}, write={:?}, exec={:?}",
20             config.read_default, config.write_default, config.exec_default);
21    println!("- Command default policies: cmd_read={:?}, cmd_exec={:?}",
22             config.cmd_read_default, config.cmd_exec_default);
23    println!("- Groups: {:?}", config.groups.keys().collect::<Vec<_>>());
24    println!("- Rule lists: {}", config.rule_lists.len());
25    
26    // Test different access scenarios including Tail-f ACM features
27    let netconf_context = RequestContext::NETCONF;
28    let cli_context = RequestContext::CLI;
29    let webui_context = RequestContext::WebUI;
30    
31    let test_cases = vec![
32        ("Admin executing edit-config (NETCONF)", AccessRequest {
33            user: "admin",
34            module_name: None,
35            rpc_name: Some("edit-config"),
36            operation: Operation::Exec,
37            path: None,
38            context: Some(&netconf_context),
39            command: None,
40        }),
41        ("Oper executing edit-config (NETCONF)", AccessRequest {
42            user: "oper",
43            module_name: None,
44            rpc_name: Some("edit-config"),
45            operation: Operation::Exec,
46            path: None,
47            context: Some(&netconf_context),
48            command: None,
49        }),
50        ("Oper modifying NACM config (NETCONF)", AccessRequest {
51            user: "oper",
52            module_name: Some("ietf-netconf-acm"),
53            rpc_name: None,
54            operation: Operation::Update,
55            path: Some("/"),
56            context: Some(&netconf_context),
57            command: None,
58        }),
59        ("Guest reading example/misc/data (NETCONF)", AccessRequest {
60            user: "Guest",
61            module_name: Some("example"),
62            rpc_name: None,
63            operation: Operation::Read,
64            path: Some("/misc/data"),
65            context: Some(&netconf_context),
66            command: None,
67        }),
68        ("Guest creating example/misc (NETCONF)", AccessRequest {
69            user: "Guest",
70            module_name: Some("example"),
71            rpc_name: None,
72            operation: Operation::Create,
73            path: Some("/misc"),
74            context: Some(&netconf_context),
75            command: None,
76        }),
77        ("Unknown user reading data (NETCONF)", AccessRequest {
78            user: "unknown",
79            module_name: Some("test"),
80            rpc_name: None,
81            operation: Operation::Read,
82            path: Some("/data"),
83            context: Some(&netconf_context),
84            command: None,
85        }),
86        // Additional test cases for context awareness
87        ("Admin via CLI (no command - should use data rules)", AccessRequest {
88            user: "admin",
89            module_name: Some("ietf-interfaces"),
90            rpc_name: None,
91            operation: Operation::Read,
92            path: Some("/interfaces"),
93            context: Some(&cli_context),
94            command: None,
95        }),
96        ("Admin via WebUI (no command - should use data rules)", AccessRequest {
97            user: "admin",
98            module_name: Some("ietf-interfaces"),
99            rpc_name: None,
100            operation: Operation::Read,
101            path: Some("/interfaces"),
102            context: Some(&webui_context),
103            command: None,
104        }),
105    ];
106    
107    println!("\nAccess validation results:");
108    for (description, request) in test_cases {
109        let result = config.validate(&request);
110        let result_str = match result.effect {
111            RuleEffect::Permit => "✅ PERMIT",
112            RuleEffect::Deny => "❌ DENY",
113        };
114        let log_str = if result.should_log { " [LOG]" } else { "" };
115        println!("- {}: {}{}", description, result_str, log_str);
116    }
117    
118    Ok(())
119}