7a3408
From 80ea7f1e17cc676c591988de47396dd24d390631 Mon Sep 17 00:00:00 2001
7a3408
Message-Id: <80ea7f1e17cc676c591988de47396dd24d390631@dist-git>
7a3408
From: Jiri Denemark <jdenemar@redhat.com>
7a3408
Date: Tue, 4 Aug 2015 14:05:52 +0200
7a3408
Subject: [PATCH] examples: Add example polkit ACL rules
7a3408
7a3408
Creating ACL rules is not exactly easy and existing examples are pretty
7a3408
simple. This patch adds a somewhat complex example which defines several
7a3408
roles. Admins can do everything, operators can do basic operations
7a3408
on any domain and several groups of users who act as operators but only
7a3408
on a limited set of domains.
7a3408
7a3408
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
7a3408
(cherry picked from commit 29b5167417483ef80f6c3fce12811b59a1e2bd55)
7a3408
7a3408
https://bugzilla.redhat.com/show_bug.cgi?id=1115289
7a3408
7a3408
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
7a3408
---
7a3408
 Makefile.am                       |   2 +-
7a3408
 configure.ac                      |   1 +
7a3408
 docs/aclpolkit.html.in            |   6 ++
7a3408
 examples/polkit/Makefile.am       |  17 +++++
7a3408
 examples/polkit/libvirt-acl.rules | 130 ++++++++++++++++++++++++++++++++++++++
7a3408
 libvirt.spec.in                   |   3 +
7a3408
 6 files changed, 158 insertions(+), 1 deletion(-)
7a3408
 create mode 100644 examples/polkit/Makefile.am
7a3408
 create mode 100644 examples/polkit/libvirt-acl.rules
7a3408
7a3408
diff --git a/Makefile.am b/Makefile.am
7a3408
index 91b943b..d338d5a 100644
7a3408
--- a/Makefile.am
7a3408
+++ b/Makefile.am
7a3408
@@ -23,7 +23,7 @@ SUBDIRS = . gnulib/lib include src daemon tools docs gnulib/tests \
7a3408
   tests po examples/object-events examples/hellolibvirt \
7a3408
   examples/dominfo examples/domsuspend examples/apparmor \
7a3408
   examples/xml/nwfilter examples/openauth examples/systemtap \
7a3408
-  tools/wireshark examples/dommigrate \
7a3408
+  tools/wireshark examples/dommigrate examples/polkit \
7a3408
   examples/lxcconvert examples/domtop
7a3408
 
7a3408
 ACLOCAL_AMFLAGS = -I m4
7a3408
diff --git a/configure.ac b/configure.ac
7a3408
index f3ae6ca..b28d990 100644
7a3408
--- a/configure.ac
7a3408
+++ b/configure.ac
7a3408
@@ -2811,6 +2811,7 @@ AC_CONFIG_FILES([\
7a3408
         examples/systemtap/Makefile \
7a3408
         examples/xml/nwfilter/Makefile \
7a3408
         examples/lxcconvert/Makefile \
7a3408
+        examples/polkit/Makefile \
7a3408
         tools/wireshark/Makefile \
7a3408
         tools/wireshark/src/Makefile])
7a3408
 AC_OUTPUT
7a3408
diff --git a/docs/aclpolkit.html.in b/docs/aclpolkit.html.in
7a3408
index e5a9b16..dae0814 100644
7a3408
--- a/docs/aclpolkit.html.in
7a3408
+++ b/docs/aclpolkit.html.in
7a3408
@@ -348,6 +348,12 @@
7a3408
       lookup method.
7a3408
     

7a3408
 
7a3408
+    

7a3408
+    See
7a3408
+    source code
7a3408
+    for a more complex example.
7a3408
+    

7a3408
+
7a3408
     

Example: restricting ability to connect to drivers

7a3408
 
7a3408
     

7a3408
diff --git a/examples/polkit/Makefile.am b/examples/polkit/Makefile.am
7a3408
new file mode 100644
7a3408
index 0000000..4d213e8
7a3408
--- /dev/null
7a3408
+++ b/examples/polkit/Makefile.am
7a3408
@@ -0,0 +1,17 @@
7a3408
+## Copyright (C) 2015 Red Hat, Inc.
7a3408
+##
7a3408
+## This library is free software; you can redistribute it and/or
7a3408
+## modify it under the terms of the GNU Lesser General Public
7a3408
+## License as published by the Free Software Foundation; either
7a3408
+## version 2.1 of the License, or (at your option) any later version.
7a3408
+##
7a3408
+## This library is distributed in the hope that it will be useful,
7a3408
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
7a3408
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
7a3408
+## Lesser General Public License for more details.
7a3408
+##
7a3408
+## You should have received a copy of the GNU Lesser General Public
7a3408
+## License along with this library.  If not, see
7a3408
+## <http://www.gnu.org/licenses/>.
7a3408
+
7a3408
+EXTRA_DIST = libvirt-acl.rules
7a3408
diff --git a/examples/polkit/libvirt-acl.rules b/examples/polkit/libvirt-acl.rules
7a3408
new file mode 100644
7a3408
index 0000000..dd68365
7a3408
--- /dev/null
7a3408
+++ b/examples/polkit/libvirt-acl.rules
7a3408
@@ -0,0 +1,130 @@
7a3408
+/*
7a3408
+ * This example defines two groups of roles any user/group can be assigned to.
7a3408
+ * An "admin" role which grants full access to all APIs on all objects to its
7a3408
+ * members, and other roles which allows their members to all APIs defined in
7a3408
+ * restrictedActions on domains matching a regular expressions assigned to
7a3408
+ * each role. (Jump below the Role class definition to see them.) Users who
7a3408
+ * belong to an "operator" role can act on any domain (matching ".*" RE),
7a3408
+ * while members of "userA", "userB", and "userC" roles are limited by more
7a3408
+ * specific REs.
7a3408
+ *
7a3408
+ * A virtualization host admin would define domains with names prefixed by
7a3408
+ * customer names and create a separate role for each customer restricting
7a3408
+ * its members to manage only domains with the corresponding prefix.
7a3408
+ */
7a3408
+
7a3408
+function Role(name) {
7a3408
+    this.name = name;
7a3408
+
7a3408
+    this.users = [];
7a3408
+    this.groups = [];
7a3408
+
7a3408
+    this.check = function(subject, api, domain) {
7a3408
+        var validUser = false
7a3408
+
7a3408
+        if (this.users.indexOf(subject.user) >= 0) {
7a3408
+            validUser = true;
7a3408
+        } else {
7a3408
+            for (var i = 0; i < subject.groups.length; i++) {
7a3408
+                if (this.groups.indexOf(subject.groups[i]) >= 0) {
7a3408
+                    validUser = true;
7a3408
+                    break;
7a3408
+                }
7a3408
+            }
7a3408
+        }
7a3408
+
7a3408
+        if (validUser &&
7a3408
+            (this.name == "admin" ||
7a3408
+             !domain ||
7a3408
+             (this.domains && domain.match(this.domains)))) {
7a3408
+            var msg = "Access granted: " +
7a3408
+                      "user = " + subject.user +
7a3408
+                      ", groups = [" + subject.groups + "]" +
7a3408
+                      ", role = " + this.name +
7a3408
+                      ", api = " + api;
7a3408
+            if (domain)
7a3408
+                msg += ", domain = " + domain;
7a3408
+            polkit.log(msg);
7a3408
+            return true
7a3408
+        }
7a3408
+
7a3408
+        return false;
7a3408
+    };
7a3408
+}
7a3408
+
7a3408
+
7a3408
+/* Basic operations and monitoring on a limited set of domains. */
7a3408
+var userA = new Role("userA");
7a3408
+userA.domains = /^a/;
7a3408
+userA.users = ["userA1", "userA2", "userA3", "multiUser"];
7a3408
+userA.groups = ["groupA1", "groupA2"];
7a3408
+
7a3408
+var userB = new Role("userB");
7a3408
+userB.domains = /^b/;
7a3408
+userB.users = ["userB1", "userB2", "userB3", "multiUser"];
7a3408
+userB.groups = ["groupB1", "groupB2", "multiGroup"];
7a3408
+
7a3408
+var userC = new Role("userC");
7a3408
+userC.domains = /^c/;
7a3408
+userC.users = ["userC1", "userC2", "userC3"];
7a3408
+userC.groups = ["groupC1", "groupC2", "multiGroup"];
7a3408
+
7a3408
+/* Same as users but on any domain. */
7a3408
+var operator = new Role("operator");
7a3408
+operator.domains = /.*/;
7a3408
+operator.users = ["powerUser1", "powerUser2"];
7a3408
+operator.groups = ["powerGroup1", "powerGroup2", "powerGroup3"];
7a3408
+
7a3408
+var users = [operator, userA, userB, userC];
7a3408
+
7a3408
+/* Full access. */
7a3408
+var admin = new Role("admin");
7a3408
+admin.users = ["adminUser1"];
7a3408
+admin.groups = ["adminGroup1"];
7a3408
+
7a3408
+
7a3408
+restrictedActions = [
7a3408
+    "domain.core-dump",
7a3408
+    "domain.fs-freeze",
7a3408
+    "domain.fs-trim",
7a3408
+    "domain.getattr",
7a3408
+    "domain.hibernate",
7a3408
+    "domain.init-control",
7a3408
+    "domain.inject-nmi",
7a3408
+    "domain.open-device",
7a3408
+    "domain.open-graphics",
7a3408
+    "domain.pm-control",
7a3408
+    "domain.read",
7a3408
+    "domain.reset",
7a3408
+    "domain.save",
7a3408
+    "domain.screenshot",
7a3408
+    "domain.send-input",
7a3408
+    "domain.send-signal",
7a3408
+    "domain.set-password",
7a3408
+    "domain.set-time",
7a3408
+    "domain.snapshot",
7a3408
+    "domain.start",
7a3408
+    "domain.stop",
7a3408
+    "domain.suspend"
7a3408
+];
7a3408
+
7a3408
+polkit.addRule(function(action, subject) {
7a3408
+    if (action.id.indexOf("org.libvirt.api.") != 0)
7a3408
+        return polkit.Result.NOT_HANDLED;
7a3408
+
7a3408
+    var api = action.id.replace("org.libvirt.api.", "");
7a3408
+    var domain = action.lookup("domain_name");
7a3408
+
7a3408
+    if (admin.check(subject, api, domain))
7a3408
+        return polkit.Result.YES;
7a3408
+
7a3408
+    if (restrictedActions.indexOf(api) < 0)
7a3408
+        return polkit.Result.NOT_HANDLED;
7a3408
+
7a3408
+    for (var i = 0; i < users.length; i++) {
7a3408
+        if (users[i].check(subject, api, domain))
7a3408
+            return polkit.Result.YES;
7a3408
+    }
7a3408
+
7a3408
+    return polkit.Result.NO;
7a3408
+});