kopia lustrzana https://github.com/simonw/datasette
/-/allow-debug tool, closes #908
rodzic
6be5654ffa
commit
12c0bc09cc
|
@ -35,6 +35,7 @@ from .views.special import (
|
|||
PatternPortfolioView,
|
||||
AuthTokenView,
|
||||
LogoutView,
|
||||
AllowDebugView,
|
||||
PermissionsDebugView,
|
||||
MessagesDebugView,
|
||||
)
|
||||
|
@ -869,6 +870,9 @@ class Datasette:
|
|||
add_route(
|
||||
MessagesDebugView.as_view(self), r"/-/messages$",
|
||||
)
|
||||
add_route(
|
||||
AllowDebugView.as_view(self), r"/-/allow-debug$",
|
||||
)
|
||||
add_route(
|
||||
PatternPortfolioView.as_view(self), r"/-/patterns$",
|
||||
)
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Debug allow rules{% endblock %}
|
||||
|
||||
{% block extra_head %}
|
||||
<style>
|
||||
textarea {
|
||||
height: 8em;
|
||||
width: 95%;
|
||||
box-sizing: border-box;
|
||||
padding: 0.5em;
|
||||
border: 2px dotted black;
|
||||
}
|
||||
.two-col {
|
||||
display: inline-block;
|
||||
width: 48%;
|
||||
}
|
||||
.two-col label {
|
||||
width: 48%;
|
||||
}
|
||||
p.message-warning {
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
@media only screen and (max-width: 576px) {
|
||||
.two-col {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<h1>Debug allow rules</h1>
|
||||
|
||||
<p>Use this tool to try out different actor and allow combinations. See <a href="https://datasette.readthedocs.io/en/stable/authentication.html#defining-permissions-with-allow-blocks">Defining permissions with "allow" blocks</a> for documentation.</p>
|
||||
|
||||
<form action="/-/allow-debug" method="get">
|
||||
<div class="two-col">
|
||||
<p><label>Actor</label></p>
|
||||
<textarea name="actor">{{ actor_input }}</textarea>
|
||||
</div>
|
||||
<div class="two-col">
|
||||
<p><label>Allow block</label></p>
|
||||
<textarea name="allow">{{ allow_input }}</textarea>
|
||||
</div>
|
||||
<div style="margin-top: 1em;">
|
||||
<input type="submit" value="Apply allow block to actor">
|
||||
</div>
|
||||
</form>
|
||||
|
||||
{% if error %}<p class="message-warning">{{ error }}</p>{% endif %}
|
||||
|
||||
{% if result == "True" %}<p class="message-info">Result: allow</p>{% endif %}
|
||||
|
||||
{% if result == "False" %}<p class="message-error">Result: deny</p>{% endif %}
|
||||
|
||||
{% endblock %}
|
|
@ -1,5 +1,6 @@
|
|||
import json
|
||||
from datasette.utils.asgi import Response, Forbidden
|
||||
from datasette.utils import actor_matches_allow
|
||||
from .base import BaseView
|
||||
import secrets
|
||||
|
||||
|
@ -107,6 +108,43 @@ class PermissionsDebugView(BaseView):
|
|||
)
|
||||
|
||||
|
||||
class AllowDebugView(BaseView):
|
||||
name = "allow_debug"
|
||||
|
||||
def __init__(self, datasette):
|
||||
self.ds = datasette
|
||||
|
||||
async def get(self, request):
|
||||
errors = []
|
||||
actor_input = request.args.get("actor") or '{"id": "root"}'
|
||||
try:
|
||||
actor = json.loads(actor_input)
|
||||
actor_input = json.dumps(actor, indent=4)
|
||||
except json.decoder.JSONDecodeError as ex:
|
||||
errors.append("Actor JSON error: {}".format(ex))
|
||||
allow_input = request.args.get("allow") or '{"id": "*"}'
|
||||
try:
|
||||
allow = json.loads(allow_input)
|
||||
allow_input = json.dumps(allow, indent=4)
|
||||
except json.decoder.JSONDecodeError as ex:
|
||||
errors.append("Allow JSON error: {}".format(ex))
|
||||
|
||||
result = None
|
||||
if not errors:
|
||||
result = str(actor_matches_allow(actor, allow))
|
||||
|
||||
return await self.render(
|
||||
["allow_debug.html"],
|
||||
request,
|
||||
{
|
||||
"result": result,
|
||||
"error": "\n\n".join(errors) if errors else "",
|
||||
"actor_input": actor_input,
|
||||
"allow_input": allow_input,
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
class MessagesDebugView(BaseView):
|
||||
name = "messages_debug"
|
||||
|
||||
|
|
|
@ -157,6 +157,13 @@ You can specify that unauthenticated actors (from anynomous HTTP requests) shoul
|
|||
|
||||
Allow keys act as an "or" mechanism. An actor will be able to execute the query if any of their JSON properties match any of the values in the corresponding lists in the ``allow`` block.
|
||||
|
||||
.. _AllowDebugView:
|
||||
|
||||
The /-/allow-debug tool
|
||||
-----------------------
|
||||
|
||||
The ``/-/allow-debug`` tool lets you try out different ``"action"`` blocks against different ``"actor"`` JSON objects. You can try that out here: https://latest.datasette.io/-/allow-debug
|
||||
|
||||
.. _authentication_permissions_metadata:
|
||||
|
||||
Configuring permissions in metadata.json
|
||||
|
|
|
@ -2,6 +2,7 @@ from .fixtures import app_client, assert_permissions_checked, make_app_client
|
|||
from bs4 import BeautifulSoup as Soup
|
||||
import copy
|
||||
import pytest
|
||||
import urllib
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
|
@ -312,6 +313,23 @@ def test_permissions_debug(app_client):
|
|||
] == checks
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"actor,allow,expected_fragment",
|
||||
[
|
||||
('{"id":"root"}', "{}", "Result: deny"),
|
||||
('{"id":"root"}', '{"id": "*"}', "Result: allow"),
|
||||
('{"', '{"id": "*"}', "Actor JSON error"),
|
||||
('{"id":"root"}', '"*"}', "Allow JSON error"),
|
||||
],
|
||||
)
|
||||
def test_allow_debug(app_client, actor, allow, expected_fragment):
|
||||
response = app_client.get(
|
||||
"/-/allow-debug?" + urllib.parse.urlencode({"actor": actor, "allow": allow})
|
||||
)
|
||||
assert 200 == response.status
|
||||
assert expected_fragment in response.text
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"allow,expected",
|
||||
[({"id": "root"}, 403), ({"id": "root", "unauthenticated": True}, 200),],
|
||||
|
|
Ładowanie…
Reference in New Issue