1use nacm_validator::{AccessRequest, NacmConfig, Operation, RuleEffect, RequestContext};
2use std::path::Path;
3
4fn main() -> Result<(), Box<dyn std::error::Error>> {
5 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 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 ("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}