File size: 2,744 Bytes
a7ffb22 b6f5bc4 a7ffb22 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | import pytest
from fastapi import Depends, FastAPI
from fastapi.testclient import TestClient
from mathly2.access import GRANTABLE, PERMISSIONS, ROLES, allowed, need, permissions_of
KNOWN = set().union(*PERMISSIONS.values()) - {"*"}
def test_there_are_five_roles_and_developer_is_never_grantable():
assert ROLES == ("student", "teacher", "manager", "admin", "developer")
assert "developer" not in GRANTABLE and set(GRANTABLE) < set(ROLES)
@pytest.mark.parametrize("role,yes,no", [
("student", {"path.use"}, {"class.teach", "class.roster", "classes.manage", "students.list", "roles.manage", "content.manage"}),
("teacher", {"path.use", "class.teach", "class.roster"}, {"classes.manage", "students.list", "roles.manage", "content.manage"}),
("manager", {"classes.manage", "class.roster", "students.list", "content.manage"}, {"path.use", "class.teach", "roles.manage"}),
("admin", {"roles.manage"}, {"path.use", "class.teach", "class.roster", "classes.manage", "students.list", "content.manage"}),
])
def test_each_role_has_only_its_permissions(role, yes, no):
for permission in yes:
assert allowed([role], permission), (role, permission)
for permission in no:
assert not allowed([role], permission), (role, permission)
def test_developer_has_every_permission_even_ones_not_invented_yet():
assert all(allowed(["developer"], p) for p in KNOWN | {"something.new"})
def test_several_roles_add_up():
assert permissions_of(["manager", "teacher"]) >= {"classes.manage", "class.teach", "path.use"}
assert not allowed([], "path.use") and permissions_of(["nonsense"]) == frozenset()
def test_manager_and_admin_see_no_learning_data():
# learning data is the student's path and a teacher's view of their own classes: neither role has them
for role in ("manager", "admin"):
assert not allowed([role], "path.use") and not allowed([role], "class.teach")
def test_need_refuses_a_missing_permission_with_403_and_a_missing_sign_in_with_401():
from mathly2.auth import DevAuthenticator
app = FastAPI()
app.state.authenticator = DevAuthenticator()
class Roles:
def resolve(self, email, source=None):
return {"boss@x.test": frozenset({"manager"})}.get(email, frozenset({"student"}))
app.state.roles = Roles()
@app.get("/manage")
def manage(user: dict = Depends(need("classes.manage"))):
return {"ok": user["email"]}
client = TestClient(app)
assert client.get("/manage").status_code == 401
assert client.get("/manage", headers={"Authorization": "Bearer dev:kid@x.test"}).status_code == 403
assert client.get("/manage", headers={"Authorization": "Bearer dev:boss@x.test"}).json() == {"ok": "boss@x.test"}
|