Can’t get PolicyKit’s ObtainAuthorization() to work.
gnome-lirc-properties, which I just mentioned needs to edit /etc/lirc/lircd.conf, which requires sudo/root access. Various APIs exist to get temporary sudo/root access but everyone now seems to agree that the new PolicyKit system is the way to go. I’d like to link to a website for it. All the system administration control panels in Ubuntu Hardy Heron seem to use PolicyKit already.
But I can’t get the thing to work, maybe because I’m using Python, and I haven’t found any help so far. I have defined the PolicyKit mechanism, but I can’t get even a simple test of the ObtainAuthorization() method to do anything interesting. This python code does not return anything other than None from ObtainAuthorization() and none of the callbacks are called:
#!/usr/bin/python import pygtk pygtk.require('2.0') import gtk import dbus import os class TestWindow: def on_button_clicked(self, widget, data=None): #Call the D-Bus method to request PolicyKit authorization: session_bus = dbus.SessionBus() policykit = session_bus.get_object('org.freedesktop.PolicyKit.AuthenticationAgent', '/', "org.gnome.PolicyKit.AuthorizationManager.SingleInstance") if(policykit == None): print("Error: Could not get PolicyKit D-Bus Interface\n") gdkwindow = self.window.window xid = gdkwindow.xid print "Calling ObtainAuthorization..." #This complains that no ObtainAuthorization(ssi) exists: #granted = policykit.ObtainAuthorization("test_action_id", xid, os.getpid()) #TODO: Neither of the async callbacks are called, and how could the return value be useful if it is async? # Note: Other code (such as gnome-panel) seems to use ShowDialog instead of ObtainAuthorization, though # ShowDialog is apparently deprecated (I don't know when), but that also has no effect. granted = policykit.ObtainAuthorization("test_action_id", xid, os.getpid(), reply_handler=self.__handleAuthReply, error_handler=self.__handleAuthError) print "...Finished." print "granted=", granted def __handleAuthReply(self, granted): print "handleAuthReply: granted\n" def __handleAuthError(self, exception): print "handleAuthError: not granted: %s\n" % exception def on_delete_event(self, widget, event, data=None): # Close the window: return False def on_destroy(self, widget, data=None): gtk.main_quit() def show(self): self.window.show() def __init__(self): self.window = gtk.Window(gtk.WINDOW_TOPLEVEL) self.window.connect("delete_event", self.on_delete_event) self.window.connect("destroy", self.on_destroy) self.button = gtk.Button("Obtain Authorization") self.button.connect("clicked", self.on_button_clicked, None) self.window.add(self.button) self.button.show() window = TestWindow() window.show() gtk.main()
gnome-lirc-properties has a real mechanism and tries to use ObtainAuthorization() for real, if someone wants to look at it properly. Here is the gnome-lirc-properties svn, and a tarball (it doesn’t do much yet).
How to use PolicyKit from an application
In return for asking the lazy web, I’ll try to describe how I think it should work, based mostly on David Zeuthen’s description. There are many opportunities to get something wrong:
- You install a D-Bus service (a PolicyKit “mechanism”) that does the thing that needs sudo access. PolicyKit will control access to this mechanism. For instance, the Clock applet’s mechanism has a SetTimeZone method. gnome-lirc-properties uses the Python D-Bus bindings to implement its mechanism. I know that our WriteConfigFile() method is far too generic, but we will improve it when we get this working.
- Update:: And this mechanism’s implementation should ask PolicyKit if it has authorization, and return an error if it doesn’t. Thanks mclasen. I’ll try to find out how to do this. Update: You can do this via the PolicyKit (on the session bus) object’s IsProcessAuthorized() method, now used in the gnome-lirc-properties PolicyKit mechanism.
- As with other D-Bus services, you install a .service file, so that D-Bus activation can start it on demand. PolicyKit mechanisms use the System bus rather than the Session bus, so you install it in $(datadir)/dbus-1/system-services (/usr/share/dbus-1/system-services on Ubuntu). Here is the .service file for gnome-lirc-properties.
- As with other D-Bus services, you install a .conf file, saying who can use the service. This is installed in $(sysconfdir)/dbus-1/system.d (/etc/dbus-1/system.d/ on Ubuntu). This is the .conf file for gnome-lirc-properties
- A .policy file tells PolicyKit who should be allowed to use the mechanism. You install this in $(datadir)/PolicyKit/policy (/usr/share/PolicyKit on Ubuntu). Here is the .policy file for gnome-lirc-properties. I believe this allows system administrators to configure access to these features via these .policy files, and I believe that is the whole point of this D-Bus “mechanism” abstraction.
- Applications that want to use this mechanism call the ObtainAuthorization() method on the “org.freedesktop.PolicyKit.AuthenticationAgent” D-Bus service, passing the action ID that is mentioned in the .policy file. If necessary, PolicyKit asks for a password (or whatever) for authentication, and presumably then gives the application the appropriate rights. The dialog uses (translatable) text from the .policy file, so it’s very specific to your application. Many applications still seem to be using the ShowDialog() method instead, but that has been deprecated.