actor_from_request for dstok_ tokens, refs #1852

pull/1912/head
Simon Willison 2022-10-25 19:18:41 -07:00
rodzic 7ab091e8ef
commit b29e487bc3
3 zmienionych plików z 59 dodań i 0 usunięć

Wyświetl plik

@ -1,5 +1,7 @@
from datasette import hookimpl
from datasette.utils import actor_matches_allow
import itsdangerous
import time
@hookimpl(tryfirst=True)
@ -45,3 +47,26 @@ def permission_allowed(datasette, actor, action, resource):
return actor_matches_allow(actor, database_allow_sql)
return inner
@hookimpl
def actor_from_request(datasette, request):
prefix = "dstok_"
authorization = request.headers.get("authorization")
if not authorization:
return None
if not authorization.startswith("Bearer "):
return None
token = authorization[len("Bearer ") :]
if not token.startswith(prefix):
return None
token = token[len(prefix) :]
try:
decoded = datasette.unsign(token, namespace="token")
except itsdangerous.BadSignature:
return None
expires_at = decoded.get("e")
if expires_at is not None:
if expires_at < time.time():
return None
return {"id": decoded["a"], "dstok": True}

Wyświetl plik

@ -62,6 +62,7 @@ class TestClient:
method="GET",
cookies=None,
if_none_match=None,
headers=None,
):
return await self._request(
path=path,
@ -70,6 +71,7 @@ class TestClient:
method=method,
cookies=cookies,
if_none_match=if_none_match,
headers=headers,
)
@async_to_sync

Wyświetl plik

@ -178,3 +178,35 @@ def test_auth_create_token(app_client, post_data, errors, expected_duration):
else:
about_right = int(time.time()) + expected_duration
assert about_right - 2 < details["e"] < about_right + 2
@pytest.mark.parametrize(
"scenario,should_work",
(
("no_token", False),
("invalid_token", False),
("expired_token", False),
("valid_unlimited_token", True),
("valid_expiring_token", True),
),
)
def test_auth_with_dstok_token(app_client, scenario, should_work):
token = None
if scenario == "valid_unlimited_token":
token = app_client.ds.sign({"a": "test"}, "token")
elif scenario == "valid_expiring_token":
token = app_client.ds.sign({"a": "test", "e": int(time.time()) + 1000}, "token")
elif scenario == "expired_token":
token = app_client.ds.sign({"a": "test", "e": int(time.time()) - 1000}, "token")
elif scenario == "invalid_token":
token = "invalid"
if token:
token = "dstok_{}".format(token)
headers = {}
if token:
headers["Authorization"] = "Bearer {}".format(token)
response = app_client.get("/-/actor.json", headers=headers)
if should_work:
assert response.json == {"actor": {"id": "test", "dstok": True}}
else:
assert response.json == {"actor": None}