diff --git a/authentik/core/api/tokens.py b/authentik/core/api/tokens.py index 7d4f6249e..3a9438294 100644 --- a/authentik/core/api/tokens.py +++ b/authentik/core/api/tokens.py @@ -2,15 +2,19 @@ from typing import Any from django.http.response import Http404 +from django_filters.rest_framework import DjangoFilterBackend from drf_spectacular.utils import OpenApiResponse, extend_schema +from guardian.shortcuts import get_anonymous_user from rest_framework.decorators import action from rest_framework.exceptions import ValidationError from rest_framework.fields import CharField +from rest_framework.filters import OrderingFilter, SearchFilter from rest_framework.request import Request from rest_framework.response import Response from rest_framework.serializers import ModelSerializer from rest_framework.viewsets import ModelViewSet +from authentik.api.authorization import OwnerPermissions from authentik.api.decorators import permission_required from authentik.core.api.used_by import UsedByMixin from authentik.core.api.users import UserSerializer @@ -79,13 +83,23 @@ class TokenViewSet(UsedByMixin, ModelViewSet): "expires", "expiring", ] - ordering = ["expires"] + ordering = ["identifier", "expires"] + permission_classes = [OwnerPermissions] + filter_backends = [DjangoFilterBackend, OrderingFilter, SearchFilter] + + def get_queryset(self): + user = self.request.user if self.request else get_anonymous_user() + if user.is_superuser: + return super().get_queryset() + return super().get_queryset().filter(user=user.pk) def perform_create(self, serializer: TokenSerializer): - serializer.save( - user=self.request.user, - expiring=self.request.user.attributes.get(USER_ATTRIBUTE_TOKEN_EXPIRING, True), - ) + if not self.request.user.is_superuser: + return serializer.save( + user=self.request.user, + expiring=self.request.user.attributes.get(USER_ATTRIBUTE_TOKEN_EXPIRING, True), + ) + return super().perform_create(serializer) @permission_required("authentik_core.view_token_key") @extend_schema( diff --git a/authentik/core/tests/test_token_api.py b/authentik/core/tests/test_token_api.py index 4a34f6bca..191d1498a 100644 --- a/authentik/core/tests/test_token_api.py +++ b/authentik/core/tests/test_token_api.py @@ -1,4 +1,6 @@ """Test token API""" +from json import loads + from django.urls.base import reverse from django.utils.timezone import now from guardian.shortcuts import get_anonymous_user @@ -13,7 +15,8 @@ class TestTokenAPI(APITestCase): def setUp(self) -> None: super().setUp() - self.user = User.objects.get(username="akadmin") + self.user = User.objects.create(username="testuser") + self.admin = User.objects.get(username="akadmin") self.client.force_login(self.user) def test_token_create(self): @@ -55,3 +58,29 @@ class TestTokenAPI(APITestCase): clean_expired_models.delay().get() token.refresh_from_db() self.assertNotEqual(key, token.key) + + def test_list(self): + """Test Token List (Test normal authentication)""" + token_should: Token = Token.objects.create( + identifier="test", expiring=False, user=self.user + ) + Token.objects.create(identifier="test-2", expiring=False, user=get_anonymous_user()) + response = self.client.get(reverse(("authentik_api:token-list"))) + body = loads(response.content) + self.assertEqual(len(body["results"]), 1) + self.assertEqual(body["results"][0]["identifier"], token_should.identifier) + + def test_list_admin(self): + """Test Token List (Test with admin auth)""" + self.client.force_login(self.admin) + token_should: Token = Token.objects.create( + identifier="test", expiring=False, user=self.user + ) + token_should_not: Token = Token.objects.create( + identifier="test-2", expiring=False, user=get_anonymous_user() + ) + response = self.client.get(reverse(("authentik_api:token-list"))) + body = loads(response.content) + self.assertEqual(len(body["results"]), 2) + self.assertEqual(body["results"][0]["identifier"], token_should.identifier) + self.assertEqual(body["results"][1]["identifier"], token_should_not.identifier) diff --git a/web/src/pages/tokens/TokenForm.ts b/web/src/pages/tokens/TokenForm.ts index 2aeaa68f3..806ffaf2c 100644 --- a/web/src/pages/tokens/TokenForm.ts +++ b/web/src/pages/tokens/TokenForm.ts @@ -7,6 +7,7 @@ import "../../elements/forms/HorizontalFormElement"; import "../../elements/forms/FormGroup"; import { dateTimeLocal, first } from "../../utils"; import { ModelForm } from "../../elements/forms/ModelForm"; +import { until } from "lit-html/directives/until"; @customElement("ak-token-form") export class TokenForm extends ModelForm { @@ -50,6 +51,27 @@ export class TokenForm extends ModelForm { ${t`Unique identifier the token is referenced by.`}

+ + +