Skip to content

Commit

Permalink
Merge branch 'main' into kerberos-source-reworked
Browse files Browse the repository at this point in the history
  • Loading branch information
rissson committed Oct 21, 2024
2 parents 3627238 + 24abe92 commit 3891204
Show file tree
Hide file tree
Showing 42 changed files with 707 additions and 390 deletions.
9 changes: 7 additions & 2 deletions authentik/core/api/devices.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,13 @@
IntegerField,
SerializerMethodField,
)
from rest_framework.permissions import IsAdminUser, IsAuthenticated
from rest_framework.permissions import IsAuthenticated
from rest_framework.request import Request
from rest_framework.response import Response
from rest_framework.viewsets import ViewSet

from authentik.core.api.utils import MetaNameSerializer
from authentik.rbac.decorators import permission_required
from authentik.stages.authenticator import device_classes, devices_for_user
from authentik.stages.authenticator.models import Device
from authentik.stages.authenticator_webauthn.models import WebAuthnDevice
Expand Down Expand Up @@ -60,7 +61,7 @@ class AdminDeviceViewSet(ViewSet):
"""Viewset for authenticator devices"""

serializer_class = DeviceSerializer
permission_classes = [IsAdminUser]
permission_classes = []

def get_devices(self, **kwargs):
"""Get all devices in all child classes"""
Expand All @@ -78,6 +79,10 @@ def get_devices(self, **kwargs):
],
responses={200: DeviceSerializer(many=True)},
)
@permission_required(
None,
[f"{model._meta.app_label}.view_{model._meta.model_name}" for model in device_classes()],
)
def list(self, request: Request) -> Response:
"""Get all devices for current user"""
kwargs = {}
Expand Down
57 changes: 57 additions & 0 deletions authentik/core/tests/test_devices_api.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
"""Test Devices API"""

from json import loads

from django.urls import reverse
from rest_framework.test import APITestCase

from authentik.core.tests.utils import create_test_admin_user, create_test_user


class TestDevicesAPI(APITestCase):
"""Test applications API"""

def setUp(self) -> None:
self.admin = create_test_admin_user()
self.user1 = create_test_user()
self.device1 = self.user1.staticdevice_set.create()
self.user2 = create_test_user()
self.device2 = self.user2.staticdevice_set.create()

def test_user_api(self):
"""Test user API"""
self.client.force_login(self.user1)
response = self.client.get(
reverse(
"authentik_api:device-list",
)
)
self.assertEqual(response.status_code, 200)
body = loads(response.content.decode())
self.assertEqual(len(body), 1)
self.assertEqual(body[0]["pk"], self.device1.pk)

def test_user_api_as_admin(self):
"""Test user API"""
self.client.force_login(self.admin)
response = self.client.get(
reverse(
"authentik_api:device-list",
)
)
self.assertEqual(response.status_code, 200)
body = loads(response.content.decode())
self.assertEqual(len(body), 0)

def test_admin_api(self):
"""Test admin API"""
self.client.force_login(self.admin)
response = self.client.get(
reverse(
"authentik_api:admin-device-list",
)
)
self.assertEqual(response.status_code, 200)
body = loads(response.content.decode())
self.assertEqual(len(body), 2)
self.assertEqual({body[0]["pk"], body[1]["pk"]}, {self.device1.pk, self.device2.pk})
2 changes: 1 addition & 1 deletion authentik/policies/event_matcher/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ def passes(self, request: PolicyRequest) -> PolicyResult:
result=result,
)
matches.append(result)
passing = any(x.passing for x in matches)
passing = all(x.passing for x in matches)
messages = chain(*[x.messages for x in matches])
result = PolicyResult(passing, *messages)
result.source_results = matches
Expand Down
15 changes: 14 additions & 1 deletion authentik/policies/event_matcher/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,11 +77,24 @@ def test_drop_multiple(self):
request = PolicyRequest(get_anonymous_user())
request.context["event"] = event
policy: EventMatcherPolicy = EventMatcherPolicy.objects.create(
client_ip="1.2.3.5", app="bar"
client_ip="1.2.3.5", app="foo"
)
response = policy.passes(request)
self.assertFalse(response.passing)

def test_multiple(self):
"""Test multiple"""
event = Event.new(EventAction.LOGIN)
event.app = "foo"
event.client_ip = "1.2.3.4"
request = PolicyRequest(get_anonymous_user())
request.context["event"] = event
policy: EventMatcherPolicy = EventMatcherPolicy.objects.create(
client_ip="1.2.3.4", app="foo"
)
response = policy.passes(request)
self.assertTrue(response.passing)

def test_invalid(self):
"""Test passing event"""
request = PolicyRequest(get_anonymous_user())
Expand Down
10 changes: 4 additions & 6 deletions authentik/providers/oauth2/views/token.py
Original file line number Diff line number Diff line change
Expand Up @@ -439,15 +439,14 @@ def __post_init_client_credentials_generated(self, request: HttpRequest):
# (22 chars being the length of the "template")
username=f"ak-{self.provider.name[:150-22]}-client_credentials",
defaults={
"attributes": {
USER_ATTRIBUTE_GENERATED: True,
},
"last_login": timezone.now(),
"name": f"Autogenerated user from application {app.name} (client credentials)",
"path": f"{USER_PATH_SYSTEM_PREFIX}/apps/{app.slug}",
"type": UserTypes.SERVICE_ACCOUNT,
},
)
self.user.attributes[USER_ATTRIBUTE_GENERATED] = True
self.user.save()
self.__check_policy_access(app, request)

Event.new(
Expand All @@ -471,9 +470,6 @@ def __create_user_from_jwt(self, token: dict[str, Any], app: Application, source
self.user, created = User.objects.update_or_create(
username=f"{self.provider.name}-{token.get('sub')}",
defaults={
"attributes": {
USER_ATTRIBUTE_GENERATED: True,
},
"last_login": timezone.now(),
"name": (
f"Autogenerated user from application {app.name} (client credentials JWT)"
Expand All @@ -482,6 +478,8 @@ def __create_user_from_jwt(self, token: dict[str, Any], app: Application, source
"type": UserTypes.SERVICE_ACCOUNT,
},
)
self.user.attributes[USER_ATTRIBUTE_GENERATED] = True
self.user.save()
exp = token.get("exp")
if created and exp:
self.user.attributes[USER_ATTRIBUTE_EXPIRES] = exp
Expand Down
2 changes: 0 additions & 2 deletions authentik/stages/authenticator_duo/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
from rest_framework.decorators import action
from rest_framework.fields import CharField, ChoiceField, IntegerField
from rest_framework.filters import OrderingFilter, SearchFilter
from rest_framework.permissions import IsAdminUser
from rest_framework.request import Request
from rest_framework.response import Response
from rest_framework.viewsets import GenericViewSet, ModelViewSet
Expand Down Expand Up @@ -197,7 +196,6 @@ class DuoDeviceViewSet(
class DuoAdminDeviceViewSet(ModelViewSet):
"""Viewset for Duo authenticator devices (for admins)"""

permission_classes = [IsAdminUser]
queryset = DuoDevice.objects.all()
serializer_class = DuoDeviceSerializer
search_fields = ["name"]
Expand Down
2 changes: 0 additions & 2 deletions authentik/stages/authenticator_sms/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
from django_filters.rest_framework.backends import DjangoFilterBackend
from rest_framework import mixins
from rest_framework.filters import OrderingFilter, SearchFilter
from rest_framework.permissions import IsAdminUser
from rest_framework.viewsets import GenericViewSet, ModelViewSet

from authentik.api.authorization import OwnerFilter, OwnerPermissions
Expand Down Expand Up @@ -76,7 +75,6 @@ class SMSDeviceViewSet(
class SMSAdminDeviceViewSet(ModelViewSet):
"""Viewset for sms authenticator devices (for admins)"""

permission_classes = [IsAdminUser]
queryset = SMSDevice.objects.all()
serializer_class = SMSDeviceSerializer
search_fields = ["name"]
Expand Down
2 changes: 0 additions & 2 deletions authentik/stages/authenticator_static/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework import mixins
from rest_framework.filters import OrderingFilter, SearchFilter
from rest_framework.permissions import IsAdminUser
from rest_framework.viewsets import GenericViewSet, ModelViewSet

from authentik.api.authorization import OwnerFilter, OwnerPermissions
Expand Down Expand Up @@ -80,7 +79,6 @@ class StaticDeviceViewSet(
class StaticAdminDeviceViewSet(ModelViewSet):
"""Viewset for static authenticator devices (for admins)"""

permission_classes = [IsAdminUser]
queryset = StaticDevice.objects.all()
serializer_class = StaticDeviceSerializer
search_fields = ["name"]
Expand Down
2 changes: 0 additions & 2 deletions authentik/stages/authenticator_totp/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
from rest_framework import mixins
from rest_framework.fields import ChoiceField
from rest_framework.filters import OrderingFilter, SearchFilter
from rest_framework.permissions import IsAdminUser
from rest_framework.viewsets import GenericViewSet, ModelViewSet

from authentik.api.authorization import OwnerFilter, OwnerPermissions
Expand Down Expand Up @@ -72,7 +71,6 @@ class TOTPDeviceViewSet(
class TOTPAdminDeviceViewSet(ModelViewSet):
"""Viewset for totp authenticator devices (for admins)"""

permission_classes = [IsAdminUser]
queryset = TOTPDevice.objects.all()
serializer_class = TOTPDeviceSerializer
search_fields = ["name"]
Expand Down
2 changes: 0 additions & 2 deletions authentik/stages/authenticator_webauthn/api/devices.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
from django_filters.rest_framework.backends import DjangoFilterBackend
from rest_framework import mixins
from rest_framework.filters import OrderingFilter, SearchFilter
from rest_framework.permissions import IsAdminUser
from rest_framework.viewsets import GenericViewSet, ModelViewSet

from authentik.api.authorization import OwnerFilter, OwnerPermissions
Expand Down Expand Up @@ -48,7 +47,6 @@ class WebAuthnDeviceViewSet(
class WebAuthnAdminDeviceViewSet(ModelViewSet):
"""Viewset for WebAuthn authenticator devices (for admins)"""

permission_classes = [IsAdminUser]
queryset = WebAuthnDevice.objects.all()
serializer_class = WebAuthnDeviceSerializer
search_fields = ["name"]
Expand Down
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,13 @@ require (
github.com/nmcclain/asn1-ber v0.0.0-20170104154839-2661553a0484
github.com/pires/go-proxyproto v0.8.0
github.com/prometheus/client_golang v1.20.5
github.com/redis/go-redis/v9 v9.6.2
github.com/redis/go-redis/v9 v9.7.0
github.com/sethvargo/go-envconfig v1.1.0
github.com/sirupsen/logrus v1.9.3
github.com/spf13/cobra v1.8.1
github.com/stretchr/testify v1.9.0
github.com/wwt/guac v1.3.2
goauthentik.io/api/v3 v3.2024083.8
goauthentik.io/api/v3 v3.2024083.10
golang.org/x/exp v0.0.0-20230210204819-062eb4c674ab
golang.org/x/oauth2 v0.23.0
golang.org/x/sync v0.8.0
Expand Down
8 changes: 4 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -248,8 +248,8 @@ github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G
github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8=
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
github.com/redis/go-redis/v9 v9.6.2 h1:w0uvkRbc9KpgD98zcvo5IrVUsn0lXpRMuhNgiHDJzdk=
github.com/redis/go-redis/v9 v9.6.2/go.mod h1:0C0c6ycQsdpVNQpxb1njEQIqkx5UcsM8FJCQLgE9+RA=
github.com/redis/go-redis/v9 v9.7.0 h1:HhLSs+B6O021gwzl+locl0zEDnyNkxMtf/Z3NNBMa9E=
github.com/redis/go-redis/v9 v9.7.0/go.mod h1:f6zhXITC7JUJIlPEiBOTXxJgPLdZcA93GewI7inzyWw=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
Expand Down Expand Up @@ -299,8 +299,8 @@ go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y
go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
goauthentik.io/api/v3 v3.2024083.8 h1:KEKPkPxfM6Mt29cp0CRusdFu7OMZlUSAtNBLz+8sBBo=
goauthentik.io/api/v3 v3.2024083.8/go.mod h1:zz+mEZg8rY/7eEjkMGWJ2DnGqk+zqxuybGCGrR2O4Kw=
goauthentik.io/api/v3 v3.2024083.10 h1:qByNsToTCHCE/C45kpZpeFqzNABEUPX3wlaY/0JJB58=
goauthentik.io/api/v3 v3.2024083.10/go.mod h1:zz+mEZg8rY/7eEjkMGWJ2DnGqk+zqxuybGCGrR2O4Kw=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
Expand Down
18 changes: 15 additions & 3 deletions locale/en/LC_MESSAGES/django.po
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-10-15 00:08+0000\n"
"POT-Creation-Date: 2024-10-18 00:09+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
Expand All @@ -18,6 +18,10 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

#: authentik/admin/models.py
msgid "Version history"
msgstr ""

#: authentik/admin/tasks.py
#, python-brace-format
msgid "New version {version} available!"
Expand Down Expand Up @@ -1373,10 +1377,18 @@ msgstr ""
msgid "Signing Key"
msgstr ""

#: authentik/providers/oauth2/models.py
msgid "Key used to sign the tokens."
msgstr ""

#: authentik/providers/oauth2/models.py
msgid "Encryption Key"
msgstr ""

#: authentik/providers/oauth2/models.py
msgid ""
"Key used to sign the tokens. Only required when JWT Algorithm is set to "
"RS256."
"Key used to encrypt the tokens. When set, tokens will be encrypted and "
"returned as JWEs."
msgstr ""

#: authentik/providers/oauth2/models.py
Expand Down
Loading

0 comments on commit 3891204

Please sign in to comment.