diff options
author | David Zeuthen <davidz@redhat.com> | 2012-05-25 17:12:17 -0400 |
---|---|---|
committer | David Zeuthen <davidz@redhat.com> | 2012-05-25 17:12:17 -0400 |
commit | d84f291cd271774129ccd7f5b8ade157f58d3282 (patch) | |
tree | 44adec9200668aab1eabe36008ba8e185dff77ec /docs | |
parent | da49ff95f2d136fd929f0ba5e75408a106f5de3b (diff) |
Rewrite the "Writing polkit applications" chapter
Signed-off-by: David Zeuthen <davidz@redhat.com>
Diffstat (limited to 'docs')
-rw-r--r-- | docs/polkit/overview.xml | 180 |
1 files changed, 142 insertions, 38 deletions
diff --git a/docs/polkit/overview.xml b/docs/polkit/overview.xml index 9f5a1a9..19834d2 100644 --- a/docs/polkit/overview.xml +++ b/docs/polkit/overview.xml @@ -20,45 +20,149 @@ <chapter id="polkit-apps"> <title>Writing polkit applications</title> <para> - polkit applications are privileged mechanisms using the - polkit authority as a decider component. To do this, a - <emphasis>mechanism</emphasis> use either - the <link linkend="ref-api">GObject API</link>, - the <link linkend="ref-dbus-api">D-Bus API</link> or - the <link linkend="pkcheck.1">pkcheck</link> command to - communicate with the polkit Authority. + polkit applications are privileged mechanisms (typically) using + the polkit authority as a decider component. They do this by + installing a <filename class='extension'>.policy</filename> file + into the + <filename class='directory'>/usr/share/polkit-1/actions</filename> + directory and communicating with the polkit authority at runtime + (either via the + <link linkend="ref-dbus-api">D-Bus API</link> or indirectly + via the + <link linkend="ref-api">libpolkit-gobject-1</link> library or the + <link linkend="pkcheck.1">pkcheck</link> command). </para> - <para> - Note that <emphasis>clients</emphasis> normally doesn't use the - polkit API directly – it is intended for privileged - <emphasis>mechanisms</emphasis>. If a client needs to disable, - modify or remove UI elements to e.g. convey to the user that a - certain action cannot be carried out (because e.g. the user is - not authorized) or authentication is needed (by e.g. displaying - a padlock icon in the UI), it is usually better to have the - mechanism provide an API for this. - </para> - <para> - If a polkit application wants to handle the case where no - authentication agent exists (for example if the app is launched - via a - <citerefentry><refentrytitle>ssh</refentrytitle><manvolnum>1</manvolnum></citerefentry> - login), it is trivial for the application to use the <link - linkend="PolkitAgentTextListener">PolkitAgentTextListener</link> - class to spawn its own authentication agent as - needed. Alternatively, the <xref linkend="pkttyagent.1"/> - helper can be used to do this. - </para> - <para> - As an example of code using the GObject API, see <xref linkend="cancel-example"/>. - For an example using the D-Bus API, see <xref linkend="polkit-raw-dbus-py"/>. - </para> - <example id="cancel-example"><title>Querying the Authority</title> - <programlisting><xi:include xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" href="../../src/examples/cancel.c"><xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting> - </example> - <example id="polkit-raw-dbus-py"><title>Accessing the Authority via D-Bus</title> - <programlisting><xi:include xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" href="../../src/examples/polkit-raw-dbus.py"><xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting> - </example> + + <simplesect id="polkit-apps-best-practices"> + <title>Best practices</title> + <itemizedlist mark='opencircle' spacing='compact'> + + <listitem><para> + <emphasis role='bold'>DO</emphasis> use polkit if you are writing a mechanism that is intended to be used by unprivileged programs. + </para></listitem> + + <listitem><para> + <emphasis role='bold'>DO</emphasis> carefully consider what actions to define. In many cases there is not a 1:1 mapping between operations and polkit actions (often a polkit action has more to do with the object the operation is acting on than the operation itself). It is important to strike the right balance between too fine-grained and too coarse-grained. + </para></listitem> + + <listitem><para> + <emphasis role='bold'>DO</emphasis> try to pick actions and implicit authorizations so applications using your mechanism will work out-of-the box for users logged in at the console (e.g. without interrupting the user with authentication dialogs). + </para></listitem> + + <listitem><para> + <emphasis role='bold'>DO</emphasis> pass polkit variables along with + <link linkend="eggdbus-method-org.freedesktop.PolicyKit1.Authority.CheckAuthorization">CheckAuthorization()</link> +requests so it's possible to write <emphasis>authorization rules</emphasis> matching on these. Also document these variables in your documentation (for example, see the +<ulink url="http://udisks.freedesktop.org/docs/latest/udisks-polkit-actions.html">udisks2 actions and variables</ulink>). + </para></listitem> + + <listitem><para> + <emphasis role='bold'>DO</emphasis> pass a customized authentication message (using the <literal>polkit.message</literal> and <literal>polkit.gettext_domain</literal> variables) that includes more detailed information about the request than whatever is declared in the <filename class='extension'>.policy</filename> file's <literal>message</literal> element. For example, it's better to show <quote>Authentication is needed to format INTEL SSDSA2MH080G1GC (/dev/sda)</quote> than just <quote>Authentication is needed to format the device</quote>. + </para></listitem> + + + <listitem><para> + <emphasis role='bold'>DON'T</emphasis> use polkit if your program isn't intended to be used by unprivileged programs. For example, if you are writing developer tools or low-level core OS command it's fine to just require the user to be root. Users can always run your tool through e.g. +<citerefentry><refentrytitle>sudo</refentrytitle><manvolnum>8</manvolnum></citerefentry>, +<link linkend="pkexec.1"><citerefentry><refentrytitle>pkexec</refentrytitle><manvolnum>1</manvolnum></citerefentry></link> +or write a simple polkit-using mechanism that allows access to a (safe) subset of your tool. + </para></listitem> + + <listitem><para> + <emphasis role='bold'>DON'T</emphasis> use polkit unless you actually have to. In other words, not every single privileged program providing a service to an unprivileged programs has to use polkit. For example, if you have a small well-written <ulink url="http://en.wikipedia.org/wiki/Setuid">setuid</ulink> helper to help deal with some implementation-detail of the OS (such as elevating the priority of the sound server process to real-time for sessions on local seats) it's not really helpful to define a polkit action for this since no-one is going to choose to not grant the privilige (in the example, no-one is going run the sound server process without real-time priority). + </para></listitem> + + <listitem><para> + <emphasis role='bold'>DON'T</emphasis> call + <link linkend="eggdbus-method-org.freedesktop.PolicyKit1.Authority.CheckAuthorization">CheckAuthorization()</link> + for all your actions every time the authority emits the + <link linkend="eggdbus-signal-org.freedesktop.PolicyKit1.Authority::Changed">Changed</link> signal. Not only is this a waste of resources, the result may also be inaccurate as authorization rules can return whatever they want, whenever they want. + </para></listitem> + + <listitem><para> + <emphasis role='bold'>DON'T</emphasis> block the main thread in your mechanism (e.g. the one used to service IPC requests from unprivileged programs) while waiting for the authority to reply - calls to + <link linkend="eggdbus-method-org.freedesktop.PolicyKit1.Authority.CheckAuthorization">CheckAuthorization()</link> + may take a very long time (seconds, even minutes) to complete as user interaction may be involved. + Instead, use either the <link linkend="polkit-authority-check-authorization">asynchronous API</link> or + a dedicated thread with the <link linkend="polkit-authority-check-authorization-sync">synchronous API</link>. + </para></listitem> + + </itemizedlist> + </simplesect> + + <simplesect id="polkit-apps-unprivileged"> + <title>Usage in unprivileged programs</title> + + <para> + Unprivileged programs consuming privileged mechanisms normally + does use polkit directly - they simply call into the mechanism + and the mechanism either renders service (or refuses the + request) after checking with polkit (which may include + presenting an authentication dialog). In either case, the + unprivileged program in question is oblivious to the fact that + polkit is being used - it simply just waits for the privileged + mechanism to carry out the request (which, if authentication + dialogs are involved may take many seconds). + </para> + <para> + Note that unprivileged programs often need to disable, modify + or remove UI elements to e.g. convey to the user that a certain + action cannot be carried out (because e.g. the user is not + authorized) or authentication is needed (by e.g. displaying a + padlock icon in the UI). + In this case, the best approach is + usually to have the unprivileged program get this information + from the privileged mechanism - especially because there often + is no reliable way that the unprivileged program can know what + polkit action is going to be used. In general, there is no + guarantee that operations (such as D-Bus methods) map 1:1: to + polkit action - for example, a disk manager service's + <literal>Format()</literal> method may check for the action + <literal>net.company.diskmanager.format-removable</literal> if + the disk is removable and + <literal>net.company.diskmanager.format-fixed</literal> + otherwise. + </para> + <para> + However, in certain cases, for example when using the + <emphasis>org.freedesktop.policykit.imply</emphasis> annotation + (see the + <link linkend="polkit.8"><citerefentry><refentrytitle>polkit</refentrytitle><manvolnum>8</manvolnum></citerefentry></link> man page), + it does make sense for an unprivileged program to query the + polkit authority (to e.g. update UI elements) and it is + in fact allowed to do so as long as the unprivileged program doesn't pass any variables along with the + <link linkend="eggdbus-method-org.freedesktop.PolicyKit1.Authority.CheckAuthorization">CheckAuthorization()</link> + call (otherwise it would be easy to spoof authentication dialogs and bypass authorization rules). + In fact, since this use-case is so common, + <link linkend="ref-api">libpolkit-gobject-1</link> provides the + <link linkend="PolkitPermission"><type>PolkitPermission</type></link> type (which is derived from + <ulink url="http://developer.gnome.org/gio/unstable/GPermission.html"><type>GPermission</type></ulink>) + that can be used together with + <ulink url="http://developer.gnome.org/gtk3/unstable/GtkLockButton.html"><type>GtkLockButton</type></ulink> + (often used to implement an + <ulink url="http://developer.gnome.org/hig-book/3.2/hig-book.html#windows-instant-apply">instant apply</ulink> + paradigm). + Note that for <type>GtkLockButton</type> to work well, the + polkit action backing it should use <literal>auth_self_keep</literal> or + <literal>auth_admin_keep</literal> for its implicit authorizations. + </para> + </simplesect> + + <simplesect id="polkit-apps-no-auth-agent"> + <title>No authentication agent</title> + <para> + If a polkit application wants to handle the case where no + authentication agent exists (for example if the app is launched + via a + <citerefentry><refentrytitle>ssh</refentrytitle><manvolnum>1</manvolnum></citerefentry> + login), the application can use the <link + linkend="PolkitAgentTextListener">PolkitAgentTextListener</link> + type to spawn its own authentication agent as + needed. Alternatively, the <xref linkend="pkttyagent.1"/> + helper can be used to do this. + </para> + </simplesect> + </chapter> <chapter id="polkit-agents"> |