summaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
authorDavid Zeuthen <davidz@redhat.com>2012-05-25 17:12:17 -0400
committerDavid Zeuthen <davidz@redhat.com>2012-05-25 17:12:17 -0400
commitd84f291cd271774129ccd7f5b8ade157f58d3282 (patch)
tree44adec9200668aab1eabe36008ba8e185dff77ec /docs
parentda49ff95f2d136fd929f0ba5e75408a106f5de3b (diff)
downloadpolkit-d84f291cd271774129ccd7f5b8ade157f58d3282.tar.gz
Rewrite the "Writing polkit applications" chapter
Signed-off-by: David Zeuthen <davidz@redhat.com>
Diffstat (limited to 'docs')
-rw-r--r--docs/polkit/overview.xml180
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">