2023-02-25 17:11:19 +00:00
|
|
|
import datetime
|
2024-10-14 12:04:39 +00:00
|
|
|
import logging
|
2023-02-25 17:11:19 +00:00
|
|
|
|
|
|
|
from werkzeug.security import gen_salt
|
|
|
|
|
2024-03-15 18:58:06 +00:00
|
|
|
from canaille.app import models
|
|
|
|
|
2023-02-25 17:11:19 +00:00
|
|
|
|
2020-08-26 14:27:08 +00:00
|
|
|
def test_no_logged_no_access(testclient):
|
2020-08-26 15:23:53 +00:00
|
|
|
testclient.get("/admin/token", status=403)
|
2020-08-26 14:27:08 +00:00
|
|
|
|
|
|
|
|
|
|
|
def test_no_admin_no_access(testclient, logged_user):
|
2020-08-26 15:23:53 +00:00
|
|
|
testclient.get("/admin/token", status=403)
|
2020-08-26 14:27:08 +00:00
|
|
|
|
|
|
|
|
|
|
|
def test_token_list(testclient, token, logged_admin):
|
2020-08-26 15:23:53 +00:00
|
|
|
res = testclient.get("/admin/token")
|
2023-03-16 15:25:14 +00:00
|
|
|
res.mustcontain(token.token_id)
|
2020-08-26 14:27:08 +00:00
|
|
|
|
|
|
|
|
2024-04-14 18:31:43 +00:00
|
|
|
def test_token_list_pagination(testclient, logged_admin, client, backend):
|
2023-02-25 17:11:19 +00:00
|
|
|
res = testclient.get("/admin/token")
|
2023-03-16 15:25:14 +00:00
|
|
|
res.mustcontain("0 items")
|
2023-02-25 17:11:19 +00:00
|
|
|
tokens = []
|
|
|
|
for _ in range(26):
|
2023-04-09 09:37:04 +00:00
|
|
|
token = models.Token(
|
2023-02-25 17:11:19 +00:00
|
|
|
token_id=gen_salt(48),
|
|
|
|
access_token="my-valid-token",
|
|
|
|
client=client,
|
|
|
|
subject=logged_admin,
|
|
|
|
type=None,
|
|
|
|
refresh_token=gen_salt(48),
|
2023-11-23 21:07:42 +00:00
|
|
|
scope=["openid", "profile"],
|
2023-03-17 23:38:56 +00:00
|
|
|
issue_date=(
|
|
|
|
datetime.datetime.now(datetime.timezone.utc).replace(microsecond=0)
|
|
|
|
),
|
2023-02-25 17:11:19 +00:00
|
|
|
lifetime=3600,
|
|
|
|
)
|
2024-04-14 18:31:43 +00:00
|
|
|
backend.save(token)
|
2023-02-25 17:11:19 +00:00
|
|
|
tokens.append(token)
|
|
|
|
|
|
|
|
res = testclient.get("/admin/token")
|
2023-03-16 15:25:14 +00:00
|
|
|
res.mustcontain("26 items")
|
2023-02-25 17:11:19 +00:00
|
|
|
token_id = res.pyquery(".tokens tbody tr td:nth-of-type(1) a").text()
|
|
|
|
assert token_id
|
|
|
|
|
2023-08-31 20:34:12 +00:00
|
|
|
form = res.forms["tableform"]
|
|
|
|
res = form.submit(name="form", value="2")
|
2023-03-09 19:46:04 +00:00
|
|
|
assert token_id not in res.pyquery(
|
|
|
|
".tokens tbody tr:nth-of-type(1) td:nth-of-type(1) a"
|
|
|
|
).text().split(" ")
|
2023-02-25 17:11:19 +00:00
|
|
|
for token in tokens:
|
2024-04-14 18:37:52 +00:00
|
|
|
backend.delete(token)
|
2023-02-25 17:11:19 +00:00
|
|
|
|
|
|
|
res = testclient.get("/admin/token")
|
2023-03-16 15:25:14 +00:00
|
|
|
res.mustcontain("0 items")
|
2023-02-25 17:11:19 +00:00
|
|
|
|
|
|
|
|
|
|
|
def test_token_list_bad_pages(testclient, logged_admin):
|
|
|
|
res = testclient.get("/admin/token")
|
2023-08-31 20:34:12 +00:00
|
|
|
form = res.forms["tableform"]
|
2023-02-25 17:11:19 +00:00
|
|
|
testclient.post(
|
2023-03-28 18:30:29 +00:00
|
|
|
"/admin/token",
|
|
|
|
{"csrf_token": form["csrf_token"].value, "page": "2"},
|
|
|
|
status=404,
|
2023-02-25 17:11:19 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
res = testclient.get("/admin/token")
|
2023-08-31 20:34:12 +00:00
|
|
|
form = res.forms["tableform"]
|
2023-02-25 17:11:19 +00:00
|
|
|
testclient.post(
|
2023-03-28 18:30:29 +00:00
|
|
|
"/admin/token",
|
|
|
|
{"csrf_token": form["csrf_token"].value, "page": "-1"},
|
|
|
|
status=404,
|
2023-02-25 17:11:19 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
|
2024-04-14 18:31:43 +00:00
|
|
|
def test_token_list_search(testclient, logged_admin, client, backend):
|
2023-04-09 09:37:04 +00:00
|
|
|
token1 = models.Token(
|
2023-03-07 17:29:18 +00:00
|
|
|
token_id=gen_salt(48),
|
|
|
|
access_token="this-token-is-ok",
|
|
|
|
client=client,
|
|
|
|
subject=logged_admin,
|
|
|
|
type=None,
|
|
|
|
refresh_token=gen_salt(48),
|
2023-11-23 21:07:42 +00:00
|
|
|
scope=["openid", "profile"],
|
2023-03-17 23:38:56 +00:00
|
|
|
issue_date=(
|
|
|
|
datetime.datetime.now(datetime.timezone.utc).replace(microsecond=0)
|
|
|
|
),
|
2023-03-07 17:29:18 +00:00
|
|
|
lifetime=3600,
|
|
|
|
)
|
2024-04-14 18:31:43 +00:00
|
|
|
backend.save(token1)
|
2023-04-09 09:37:04 +00:00
|
|
|
token2 = models.Token(
|
2023-03-07 17:29:18 +00:00
|
|
|
token_id=gen_salt(48),
|
|
|
|
access_token="this-token-is-valid",
|
|
|
|
client=client,
|
|
|
|
subject=logged_admin,
|
|
|
|
type=None,
|
|
|
|
refresh_token=gen_salt(48),
|
2023-11-23 21:07:42 +00:00
|
|
|
scope=["openid", "profile"],
|
2023-03-17 23:38:56 +00:00
|
|
|
issue_date=(
|
|
|
|
datetime.datetime.now(datetime.timezone.utc).replace(microsecond=0)
|
|
|
|
),
|
2023-03-07 17:29:18 +00:00
|
|
|
lifetime=3600,
|
|
|
|
)
|
2024-04-14 18:31:43 +00:00
|
|
|
backend.save(token2)
|
2023-03-07 17:29:18 +00:00
|
|
|
|
|
|
|
res = testclient.get("/admin/token")
|
2023-03-16 15:25:14 +00:00
|
|
|
res.mustcontain("2 items")
|
|
|
|
res.mustcontain(token1.token_id)
|
|
|
|
res.mustcontain(token2.token_id)
|
2023-03-07 17:29:18 +00:00
|
|
|
|
|
|
|
form = res.forms["search"]
|
|
|
|
form["query"] = "valid"
|
|
|
|
res = form.submit()
|
|
|
|
|
2023-06-30 15:42:16 +00:00
|
|
|
res.mustcontain("1 item")
|
2023-03-16 15:25:14 +00:00
|
|
|
res.mustcontain(token2.token_id)
|
|
|
|
res.mustcontain(no=token1.token_id)
|
2023-03-07 17:29:18 +00:00
|
|
|
|
|
|
|
|
2020-08-26 14:27:08 +00:00
|
|
|
def test_token_view(testclient, token, logged_admin):
|
2022-02-16 17:00:30 +00:00
|
|
|
res = testclient.get("/admin/token/" + token.token_id)
|
2023-03-16 15:25:14 +00:00
|
|
|
res.mustcontain(token.access_token)
|
2022-03-03 09:05:14 +00:00
|
|
|
|
|
|
|
|
|
|
|
def test_token_not_found(testclient, logged_admin):
|
2023-05-25 11:37:58 +00:00
|
|
|
testclient.get("/admin/token/" + "yolo", status=404)
|
2023-02-04 17:41:49 +00:00
|
|
|
|
|
|
|
|
2023-07-06 16:43:37 +00:00
|
|
|
def test_revoke_bad_request(testclient, token, logged_admin):
|
|
|
|
assert not token.revoked
|
|
|
|
|
|
|
|
res = testclient.get(f"/admin/token/{token.token_id}")
|
|
|
|
res = res.form.submit(name="action", value="invalid", status=400)
|
|
|
|
|
|
|
|
|
2024-10-14 12:04:39 +00:00
|
|
|
def test_revoke_token(testclient, token, logged_admin, backend, caplog):
|
2023-02-04 17:41:49 +00:00
|
|
|
assert not token.revoked
|
|
|
|
|
2023-07-06 16:43:37 +00:00
|
|
|
res = testclient.get(f"/admin/token/{token.token_id}")
|
|
|
|
res = res.form.submit(name="action", value="confirm-revoke")
|
|
|
|
res = res.form.submit(name="action", value="revoke")
|
2023-02-04 17:41:49 +00:00
|
|
|
assert ("success", "The token has successfully been revoked.") in res.flashes
|
2024-10-14 12:04:39 +00:00
|
|
|
assert (
|
|
|
|
"canaille",
|
2024-10-21 09:17:55 +00:00
|
|
|
logging.SECURITY,
|
|
|
|
"Revoked token for user in client Some client by admin from unknown IP",
|
2024-10-14 12:04:39 +00:00
|
|
|
) in caplog.record_tuples
|
2023-02-04 17:41:49 +00:00
|
|
|
|
2024-04-14 20:51:58 +00:00
|
|
|
backend.reload(token)
|
2023-02-04 17:41:49 +00:00
|
|
|
assert token.revoked
|
|
|
|
|
|
|
|
|
|
|
|
def test_revoke_invalid_token(testclient, logged_admin):
|
2023-05-25 11:37:58 +00:00
|
|
|
testclient.get("/admin/token/invalid/revoke", status=404)
|