core: allow admins to create tokens with all parameters, re-add user to token form

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
This commit is contained in:
Jens Langhammer 2021-09-19 15:25:48 +02:00
parent 663dffd8be
commit c85484fc00
3 changed files with 71 additions and 6 deletions

View File

@ -2,15 +2,19 @@
from typing import Any from typing import Any
from django.http.response import Http404 from django.http.response import Http404
from django_filters.rest_framework import DjangoFilterBackend
from drf_spectacular.utils import OpenApiResponse, extend_schema from drf_spectacular.utils import OpenApiResponse, extend_schema
from guardian.shortcuts import get_anonymous_user
from rest_framework.decorators import action from rest_framework.decorators import action
from rest_framework.exceptions import ValidationError from rest_framework.exceptions import ValidationError
from rest_framework.fields import CharField from rest_framework.fields import CharField
from rest_framework.filters import OrderingFilter, SearchFilter
from rest_framework.request import Request from rest_framework.request import Request
from rest_framework.response import Response from rest_framework.response import Response
from rest_framework.serializers import ModelSerializer from rest_framework.serializers import ModelSerializer
from rest_framework.viewsets import ModelViewSet from rest_framework.viewsets import ModelViewSet
from authentik.api.authorization import OwnerPermissions
from authentik.api.decorators import permission_required from authentik.api.decorators import permission_required
from authentik.core.api.used_by import UsedByMixin from authentik.core.api.used_by import UsedByMixin
from authentik.core.api.users import UserSerializer from authentik.core.api.users import UserSerializer
@ -79,13 +83,23 @@ class TokenViewSet(UsedByMixin, ModelViewSet):
"expires", "expires",
"expiring", "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): def perform_create(self, serializer: TokenSerializer):
serializer.save( if not self.request.user.is_superuser:
user=self.request.user, return serializer.save(
expiring=self.request.user.attributes.get(USER_ATTRIBUTE_TOKEN_EXPIRING, True), 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") @permission_required("authentik_core.view_token_key")
@extend_schema( @extend_schema(

View File

@ -1,4 +1,6 @@
"""Test token API""" """Test token API"""
from json import loads
from django.urls.base import reverse from django.urls.base import reverse
from django.utils.timezone import now from django.utils.timezone import now
from guardian.shortcuts import get_anonymous_user from guardian.shortcuts import get_anonymous_user
@ -13,7 +15,8 @@ class TestTokenAPI(APITestCase):
def setUp(self) -> None: def setUp(self) -> None:
super().setUp() 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) self.client.force_login(self.user)
def test_token_create(self): def test_token_create(self):
@ -55,3 +58,29 @@ class TestTokenAPI(APITestCase):
clean_expired_models.delay().get() clean_expired_models.delay().get()
token.refresh_from_db() token.refresh_from_db()
self.assertNotEqual(key, token.key) 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)

View File

@ -7,6 +7,7 @@ import "../../elements/forms/HorizontalFormElement";
import "../../elements/forms/FormGroup"; import "../../elements/forms/FormGroup";
import { dateTimeLocal, first } from "../../utils"; import { dateTimeLocal, first } from "../../utils";
import { ModelForm } from "../../elements/forms/ModelForm"; import { ModelForm } from "../../elements/forms/ModelForm";
import { until } from "lit-html/directives/until";
@customElement("ak-token-form") @customElement("ak-token-form")
export class TokenForm extends ModelForm<Token, string> { export class TokenForm extends ModelForm<Token, string> {
@ -50,6 +51,27 @@ export class TokenForm extends ModelForm<Token, string> {
${t`Unique identifier the token is referenced by.`} ${t`Unique identifier the token is referenced by.`}
</p> </p>
</ak-form-element-horizontal> </ak-form-element-horizontal>
<ak-form-element-horizontal label=${t`User`} ?required=${true} name="user">
<select class="pf-c-form-control">
${until(
new CoreApi(DEFAULT_CONFIG)
.coreUsersList({
ordering: "username",
})
.then((users) => {
return users.results.map((user) => {
return html`<option
value=${user.pk}
?selected=${this.instance?.user === user.pk}
>
${user.username}
</option>`;
});
}),
html`<option>${t`Loading...`}</option>`,
)}
</select>
</ak-form-element-horizontal>
<ak-form-element-horizontal label=${t`Intent`} ?required=${true} name="intent"> <ak-form-element-horizontal label=${t`Intent`} ?required=${true} name="intent">
<select class="pf-c-form-control"> <select class="pf-c-form-control">
<option <option