Removed resource_type from permissions system, closes #817

Refs #811, #699
This commit is contained in:
Simon Willison 2020-06-08 11:51:03 -07:00
commit c9f1ec616e
14 changed files with 39 additions and 89 deletions

View file

@ -465,7 +465,7 @@ class Datasette:
return []
async def permission_allowed(
self, actor, action, resource_type=None, resource_identifier=None, default=False
self, actor, action, resource_identifier=None, default=False
):
"Check permissions using the permissions_allowed plugin hook"
result = None
@ -473,7 +473,6 @@ class Datasette:
datasette=self,
actor=actor,
action=action,
resource_type=resource_type,
resource_identifier=resource_identifier,
):
if callable(check):
@ -491,7 +490,6 @@ class Datasette:
"when": datetime.datetime.utcnow().isoformat(),
"actor": actor,
"action": action,
"resource_type": resource_type,
"resource_identifier": resource_identifier,
"used_default": used_default,
"result": result,

View file

@ -3,7 +3,7 @@ from datasette.utils import actor_matches_allow
@hookimpl
def permission_allowed(datasette, actor, action, resource_type, resource_identifier):
def permission_allowed(datasette, actor, action, resource_identifier):
if action == "permissions-debug":
if actor and actor.get("id") == "root":
return True
@ -12,13 +12,11 @@ def permission_allowed(datasette, actor, action, resource_type, resource_identif
if allow is not None:
return actor_matches_allow(actor, allow)
elif action == "view-database":
assert resource_type == "database"
database_allow = datasette.metadata("allow", database=resource_identifier)
if database_allow is None:
return True
return actor_matches_allow(actor, database_allow)
elif action == "view-table":
assert resource_type == "table"
database, table = resource_identifier
tables = datasette.metadata("tables", database=database) or {}
table_allow = (tables.get(table) or {}).get("allow")
@ -27,7 +25,6 @@ def permission_allowed(datasette, actor, action, resource_type, resource_identif
return actor_matches_allow(actor, table_allow)
elif action == "view-query":
# Check if this query has a "allow" block in metadata
assert resource_type == "query"
database, query_name = resource_identifier
queries_metadata = datasette.metadata("queries", database=database)
assert query_name in queries_metadata

View file

@ -66,5 +66,5 @@ def actor_from_request(datasette, request):
@hookspec
def permission_allowed(datasette, actor, action, resource_type, resource_identifier):
def permission_allowed(datasette, actor, action, resource_identifier):
"Check if actor is allowed to perfom this action - return True, False or None"

View file

@ -46,8 +46,8 @@
{% endif %}
</h2>
<p><strong>Actor:</strong> {{ check.actor|tojson }}</p>
{% if check.resource_type %}
<p><strong>Resource:</strong> {{ check.resource_type }} = {{ check.resource_identifier }}</p>
{% if check.resource_identifier %}
<p><strong>Resource:</strong> {{ check.resource_identifier }}</p>
{% endif %}
</div>
{% endfor %}

View file

@ -876,24 +876,14 @@ def actor_matches_allow(actor, allow):
return False
async def check_visibility(
datasette, actor, action, resource_type, resource_identifier, default=True
):
async def check_visibility(datasette, actor, action, resource_identifier, default=True):
"Returns (visible, private) - visible = can you see it, private = can others see it too"
visible = await datasette.permission_allowed(
actor,
action,
resource_type=resource_type,
resource_identifier=resource_identifier,
default=default,
actor, action, resource_identifier=resource_identifier, default=default,
)
if not visible:
return (False, False)
private = not await datasette.permission_allowed(
None,
action,
resource_type=resource_type,
resource_identifier=resource_identifier,
default=default,
None, action, resource_identifier=resource_identifier, default=default,
)
return visible, private

View file

@ -64,13 +64,10 @@ class BaseView(AsgiView):
response.body = b""
return response
async def check_permission(
self, request, action, resource_type=None, resource_identifier=None
):
async def check_permission(self, request, action, resource_identifier=None):
ok = await self.ds.permission_allowed(
request.actor,
action,
resource_type=resource_type,
resource_identifier=resource_identifier,
default=True,
)

View file

@ -21,7 +21,7 @@ class DatabaseView(DataView):
async def data(self, request, database, hash, default_labels=False, _size=None):
await self.check_permission(request, "view-instance")
await self.check_permission(request, "view-database", "database", database)
await self.check_permission(request, "view-database", database)
metadata = (self.ds.metadata("databases") or {}).get(database, {})
self.ds.update_with_inherited_metadata(metadata)
@ -43,7 +43,7 @@ class DatabaseView(DataView):
views = []
for view_name in await db.view_names():
visible, private = await check_visibility(
self.ds, request.actor, "view-table", "table", (database, view_name),
self.ds, request.actor, "view-table", (database, view_name),
)
if visible:
views.append(
@ -53,7 +53,7 @@ class DatabaseView(DataView):
tables = []
for table in table_counts:
visible, private = await check_visibility(
self.ds, request.actor, "view-table", "table", (database, table),
self.ds, request.actor, "view-table", (database, table),
)
if not visible:
continue
@ -75,11 +75,7 @@ class DatabaseView(DataView):
canned_queries = []
for query in self.ds.get_canned_queries(database):
visible, private = await check_visibility(
self.ds,
request.actor,
"view-query",
"query",
(database, query["name"]),
self.ds, request.actor, "view-query", (database, query["name"]),
)
if visible:
canned_queries.append(dict(query, private=private))
@ -112,10 +108,8 @@ class DatabaseDownload(DataView):
async def view_get(self, request, database, hash, correct_hash_present, **kwargs):
await self.check_permission(request, "view-instance")
await self.check_permission(request, "view-database", "database", database)
await self.check_permission(
request, "view-database-download", "database", database
)
await self.check_permission(request, "view-database", database)
await self.check_permission(request, "view-database-download", database)
if database not in self.ds.databases:
raise DatasetteError("Invalid database", status=404)
db = self.ds.databases[database]
@ -155,17 +149,15 @@ class QueryView(DataView):
# Respect canned query permissions
await self.check_permission(request, "view-instance")
await self.check_permission(request, "view-database", "database", database)
await self.check_permission(request, "view-database", database)
private = False
if canned_query:
await self.check_permission(
request, "view-query", "query", (database, canned_query)
)
await self.check_permission(request, "view-query", (database, canned_query))
private = not await self.ds.permission_allowed(
None, "view-query", "query", (database, canned_query), default=True
None, "view-query", (database, canned_query), default=True
)
else:
await self.check_permission(request, "execute-sql", "database", database)
await self.check_permission(request, "execute-sql", database)
# Extract any :named parameters
named_parameters = named_parameters or self.re_named_parameter.findall(sql)
named_parameter_values = {

View file

@ -26,7 +26,7 @@ class IndexView(BaseView):
databases = []
for name, db in self.ds.databases.items():
visible, database_private = await check_visibility(
self.ds, request.actor, "view-database", "database", name,
self.ds, request.actor, "view-database", name,
)
if not visible:
continue
@ -36,7 +36,7 @@ class IndexView(BaseView):
views = []
for view_name in await db.view_names():
visible, private = await check_visibility(
self.ds, request.actor, "view-table", "table", (name, view_name),
self.ds, request.actor, "view-table", (name, view_name),
)
if visible:
views.append({"name": view_name, "private": private})
@ -52,7 +52,7 @@ class IndexView(BaseView):
tables = {}
for table in table_names:
visible, private = await check_visibility(
self.ds, request.actor, "view-table", "table", (name, table),
self.ds, request.actor, "view-table", (name, table),
)
if not visible:
continue

View file

@ -268,11 +268,11 @@ class TableView(RowTableShared):
raise NotFound("Table not found: {}".format(table))
await self.check_permission(request, "view-instance")
await self.check_permission(request, "view-database", "database", database)
await self.check_permission(request, "view-table", "table", (database, table))
await self.check_permission(request, "view-database", database)
await self.check_permission(request, "view-table", (database, table))
private = not await self.ds.permission_allowed(
None, "view-table", "table", (database, table), default=True
None, "view-table", (database, table), default=True
)
pks = await db.primary_keys(table)
@ -854,8 +854,8 @@ class RowView(RowTableShared):
async def data(self, request, database, hash, table, pk_path, default_labels=False):
pk_values = urlsafe_components(pk_path)
await self.check_permission(request, "view-instance")
await self.check_permission(request, "view-database", "database", database)
await self.check_permission(request, "view-table", "table", (database, table))
await self.check_permission(request, "view-database", database)
await self.check_permission(request, "view-table", (database, table))
db = self.ds.databases[database]
pks = await db.primary_keys(table)
use_rowid = not pks