Skip to content

Commit

Permalink
Better example plugin for permission_allowed
Browse files Browse the repository at this point in the history
Also fixed it so default permission checks run after plugin permission checks, refs #818
  • Loading branch information
simonw committed Jun 8, 2020
1 parent 8205d58 commit e0a4664
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 5 deletions.
2 changes: 1 addition & 1 deletion datasette/default_permissions.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from datasette.utils import actor_matches_allow


@hookimpl
@hookimpl(tryfirst=True)
def permission_allowed(datasette, actor, action, resource):
if action == "permissions-debug":
if actor and actor.get("id") == "root":
Expand Down
4 changes: 2 additions & 2 deletions docs/authentication.rst
Original file line number Diff line number Diff line change
Expand Up @@ -174,11 +174,11 @@ To limit access to the ``users`` table in your ``bakery.db`` database:
This works for SQL views as well - you can treat them as if they are tables.

.. warning::
Restricting access to tables and views in this way will NOT prevent users from querying them using arbitrary SQL queries.
Restricting access to tables and views in this way will NOT prevent users from querying them using arbitrary SQL queries, `like this <https://latest.datasette.io/fixtures?sql=select+*+from+facetable>`__ for example.

If you are restricting access to specific tables you should also use the ``"allow_sql"`` block to prevent users from accessing

.. _authentication_permissions_table:
.. _authentication_permissions_query:

Controlling access to specific canned queries
---------------------------------------------
Expand Down
40 changes: 38 additions & 2 deletions docs/plugins.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1006,7 +1006,7 @@ Instead of returning a dictionary, this function can return an awaitable functio
.. _plugin_permission_allowed:

permission_allowed(datasette, actor, action, resource)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

``datasette`` - :ref:`internals_datasette`
You can use this to access plugin configuration options via ``datasette.plugin_config(your_plugin_name)``, or to execute SQL queries.
Expand All @@ -1022,4 +1022,40 @@ permission_allowed(datasette, actor, action, resource)

Called to check that an actor has permission to perform an action on a resource. Can return ``True`` if the action is allowed, ``False`` if the action is not allowed or ``None`` if the plugin does not have an opinion one way or the other.

See :ref:`permissions` for a full list of permissions included in Datasette core.
Here's an example plugin which randomly selects if a permission should be allowed or denied, except for ``view-instance`` which always uses the default permission scheme instead.

.. code-block:: python
from datasette import hookimpl
import random
@hookimpl
def permission_allowed(action):
if action != "view-instance":
# Return True or False at random
return random.random() > 0.5
# Returning None falls back to default permissions
This function can alternatively return an awaitable function which itself returns ``True``, ``False`` or ``None``. You can use this option if you need to execute additional database queries using ``await datasette.execute(...)``.

Here's an example that allows users to view the ``admin_log`` table only if their actor ``id`` is present in the ``admin_users`` table. It aso disallows arbitrary SQL queries for the ``staff.db`` database for all users.

.. code-block:: python
@hookimpl
def permission_allowed(datasette, actor, action, resource):
async def inner():
if action == "execute-sql" and resource == "staff":
return False
if action == "view-table" and resource == ("staff", "admin_log"):
if not actor:
return False
user_id = actor["id"]
return await datasette.get_database("staff").execute(
"select count(*) from admin_users where user_id = :user_id",
{"user_id": user_id},
)
return inner
See :ref:`permissions` for a full list of permissions that are included in Datasette core.

0 comments on commit e0a4664

Please sign in to comment.