From c85484fc00f45e4f2b552c70fe7d1e64762229f7 Mon Sep 17 00:00:00 2001
From: Jens Langhammer
Date: Sun, 19 Sep 2021 15:25:48 +0200
Subject: [PATCH] core: allow admins to create tokens with all parameters,
re-add user to token form
Signed-off-by: Jens Langhammer
---
authentik/core/api/tokens.py | 24 +++++++++++++++-----
authentik/core/tests/test_token_api.py | 31 +++++++++++++++++++++++++-
web/src/pages/tokens/TokenForm.ts | 22 ++++++++++++++++++
3 files changed, 71 insertions(+), 6 deletions(-)
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.`}
+
+
+