]> git.proxmox.com Git - proxmox.git/commitdiff
router: permissions: allow to pass partial-collapsed acl path components
authorThomas Lamprecht <t.lamprecht@proxmox.com>
Thu, 28 Apr 2022 11:27:02 +0000 (13:27 +0200)
committerThomas Lamprecht <t.lamprecht@proxmox.com>
Thu, 5 May 2022 06:54:14 +0000 (08:54 +0200)
This would allow the following components:

* all in one : &["system/network"]
* mixed: &["system/network", "dns"]
* with templates: &["datastore/{store}"]
* with the value of template being a path, e,g, with ns = "foo/bar":
  &["/datastore/{store}/{ns}"]

Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
proxmox-router/src/permission.rs

index 34b3bff8a72ce8a2f6ca77d3d8b2c551b1962179..f861b349d3ae36a4e0375ae6ab87b7874be09a75 100644 (file)
@@ -145,17 +145,22 @@ fn check_api_permission_tail(
         Permission::Privilege(path, expected_privs, partial) => {
             // replace uri vars
             let mut new_path: Vec<&str> = Vec::new();
-            for comp in path.iter() {
-                if comp.starts_with('{') && comp.ends_with('}') {
-                    let param_name = unsafe { comp.get_unchecked(1..comp.len() - 1) };
-                    match param.get(param_name) {
-                        None => return false,
-                        Some(value) => {
-                            new_path.push(value);
+            for outer in path.iter() {
+                // we can have a whole priv path as one component, e.g., for Namespaces
+                for comp in outer.split('/') {
+                    if comp.starts_with('{') && comp.ends_with('}') {
+                        let param_name = unsafe { comp.get_unchecked(1..comp.len() - 1) };
+                        match param.get(param_name) {
+                            None => return false,
+                            Some(value) => {
+                                for subcomp in value.split('/') {
+                                    new_path.push(subcomp);
+                                }
+                            }
                         }
+                    } else {
+                        new_path.push(comp);
                     }
-                } else {
-                    new_path.push(comp);
                 }
             }
             match userid {
@@ -244,6 +249,9 @@ mod test {
                 "/datastore/foo": {
                     "user1": 0b01,
                 },
+                "/datastore/foo/bar/baz": {
+                    "user1": 0b01,
+                },
             }),
             groups: json!({
                 "user1": [
@@ -258,6 +266,7 @@ mod test {
         let mut param = HashMap::new();
         param.insert("user".to_string(), "user1".to_string());
         param.insert("datastore".to_string(), "foo".to_string());
+        param.insert("ns".to_string(), "bar/baz".to_string());
 
         let test_check = |perm: &Permission, userid: Option<&str>, should_succeed: bool| {
             println!("{:?} on {:?}: {}", userid, perm, should_succeed);
@@ -403,5 +412,37 @@ mod test {
             None,
             false,
         );
+        // namespace test where {ns} is a combined variable that needs to be split
+        test_check(
+            &Permission::Privilege(&["datastore", "{datastore}", "{ns}"], 0b01, true),
+            Some("user1"),
+            true,
+        );
+        test_check(
+            &Permission::Privilege(&["datastore", "{datastore}", "{ns}"], 0b01, true),
+            Some("user2"),
+            false,
+        );
+        test_check(
+            &Permission::Privilege(&["datastore", "{datastore}", "{ns}"], 0b01, true),
+            None,
+            false,
+        );
+        // like above but now even the path itself is combined
+        test_check(
+            &Permission::Privilege(&["datastore", "{datastore}/{ns}"], 0b01, true),
+            Some("user1"),
+            true,
+        );
+        test_check(
+            &Permission::Privilege(&["datastore", "{datastore}/{ns}"], 0b01, true),
+            Some("user2"),
+            false,
+        );
+        test_check(
+            &Permission::Privilege(&["datastore", "{datastore}/{ns}"], 0b01, true),
+            None,
+            false,
+        );
     }
 }