mirror of
https://github.com/simonw/datasette.git
synced 2025-12-10 16:51:24 +01:00
Mechanism to prevent tokens creating tokens, closes #1857
This commit is contained in:
parent
b29e487bc3
commit
0f013ff497
4 changed files with 17 additions and 2 deletions
|
|
@ -69,4 +69,4 @@ def actor_from_request(datasette, request):
|
||||||
if expires_at is not None:
|
if expires_at is not None:
|
||||||
if expires_at < time.time():
|
if expires_at < time.time():
|
||||||
return None
|
return None
|
||||||
return {"id": decoded["a"], "dstok": True}
|
return {"id": decoded["a"], "token": "dstok"}
|
||||||
|
|
|
||||||
|
|
@ -177,6 +177,10 @@ class CreateTokenView(BaseView):
|
||||||
raise Forbidden(
|
raise Forbidden(
|
||||||
"You must be logged in as an actor with an ID to create a token"
|
"You must be logged in as an actor with an ID to create a token"
|
||||||
)
|
)
|
||||||
|
if request.actor.get("token"):
|
||||||
|
raise Forbidden(
|
||||||
|
"Token authentication cannot be used to create additional tokens"
|
||||||
|
)
|
||||||
|
|
||||||
async def get(self, request):
|
async def get(self, request):
|
||||||
self.check_permission(request)
|
self.check_permission(request)
|
||||||
|
|
|
||||||
|
|
@ -348,6 +348,8 @@ A token created by a user will include that user's ``"id"`` in the token payload
|
||||||
|
|
||||||
Coming soon: a mechanism for creating tokens that can only perform a subset of the actions available to the user who created them.
|
Coming soon: a mechanism for creating tokens that can only perform a subset of the actions available to the user who created them.
|
||||||
|
|
||||||
|
This page cannot be accessed by actors with a ``"token": "some-value"`` property. This is to prevent API tokens from being used to automatically create more tokens. Datasette plugins that implement their own form of API token authentication should follow this convention.
|
||||||
|
|
||||||
.. _permissions_plugins:
|
.. _permissions_plugins:
|
||||||
|
|
||||||
Checking permissions in plugins
|
Checking permissions in plugins
|
||||||
|
|
|
||||||
|
|
@ -180,6 +180,15 @@ def test_auth_create_token(app_client, post_data, errors, expected_duration):
|
||||||
assert about_right - 2 < details["e"] < about_right + 2
|
assert about_right - 2 < details["e"] < about_right + 2
|
||||||
|
|
||||||
|
|
||||||
|
def test_auth_create_token_not_allowed_for_tokens(app_client):
|
||||||
|
ds_tok = app_client.ds.sign({"a": "test", "token": "dstok"}, "token")
|
||||||
|
response = app_client.get(
|
||||||
|
"/-/create-token",
|
||||||
|
headers={"Authorization": "Bearer dstok_{}".format(ds_tok)},
|
||||||
|
)
|
||||||
|
assert response.status == 403
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"scenario,should_work",
|
"scenario,should_work",
|
||||||
(
|
(
|
||||||
|
|
@ -207,6 +216,6 @@ def test_auth_with_dstok_token(app_client, scenario, should_work):
|
||||||
headers["Authorization"] = "Bearer {}".format(token)
|
headers["Authorization"] = "Bearer {}".format(token)
|
||||||
response = app_client.get("/-/actor.json", headers=headers)
|
response = app_client.get("/-/actor.json", headers=headers)
|
||||||
if should_work:
|
if should_work:
|
||||||
assert response.json == {"actor": {"id": "test", "dstok": True}}
|
assert response.json == {"actor": {"id": "test", "token": "dstok"}}
|
||||||
else:
|
else:
|
||||||
assert response.json == {"actor": None}
|
assert response.json == {"actor": None}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue