kopia lustrzana https://github.com/simonw/datasette
actor_from_request for dstok_ tokens, refs #1852
rodzic
7ab091e8ef
commit
b29e487bc3
|
@ -1,5 +1,7 @@
|
||||||
from datasette import hookimpl
|
from datasette import hookimpl
|
||||||
from datasette.utils import actor_matches_allow
|
from datasette.utils import actor_matches_allow
|
||||||
|
import itsdangerous
|
||||||
|
import time
|
||||||
|
|
||||||
|
|
||||||
@hookimpl(tryfirst=True)
|
@hookimpl(tryfirst=True)
|
||||||
|
@ -45,3 +47,26 @@ def permission_allowed(datasette, actor, action, resource):
|
||||||
return actor_matches_allow(actor, database_allow_sql)
|
return actor_matches_allow(actor, database_allow_sql)
|
||||||
|
|
||||||
return inner
|
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}
|
||||||
|
|
|
@ -62,6 +62,7 @@ class TestClient:
|
||||||
method="GET",
|
method="GET",
|
||||||
cookies=None,
|
cookies=None,
|
||||||
if_none_match=None,
|
if_none_match=None,
|
||||||
|
headers=None,
|
||||||
):
|
):
|
||||||
return await self._request(
|
return await self._request(
|
||||||
path=path,
|
path=path,
|
||||||
|
@ -70,6 +71,7 @@ class TestClient:
|
||||||
method=method,
|
method=method,
|
||||||
cookies=cookies,
|
cookies=cookies,
|
||||||
if_none_match=if_none_match,
|
if_none_match=if_none_match,
|
||||||
|
headers=headers,
|
||||||
)
|
)
|
||||||
|
|
||||||
@async_to_sync
|
@async_to_sync
|
||||||
|
|
|
@ -178,3 +178,35 @@ def test_auth_create_token(app_client, post_data, errors, expected_duration):
|
||||||
else:
|
else:
|
||||||
about_right = int(time.time()) + expected_duration
|
about_right = int(time.time()) + expected_duration
|
||||||
assert about_right - 2 < details["e"] < about_right + 2
|
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}
|
||||||
|
|
Ładowanie…
Reference in New Issue