diff --git a/authentik/stages/authenticator_mobile/api.py b/authentik/stages/authenticator_mobile/api.py index 4816aec93..513831c2a 100644 --- a/authentik/stages/authenticator_mobile/api.py +++ b/authentik/stages/authenticator_mobile/api.py @@ -1,12 +1,10 @@ -"""AuthenticatorDuoStage API Views""" -from django.http import Http404 +"""AuthenticatorMobileStage API Views""" from django_filters.rest_framework.backends import DjangoFilterBackend from drf_spectacular.types import OpenApiTypes -from drf_spectacular.utils import OpenApiResponse, extend_schema, inline_serializer -from guardian.shortcuts import get_objects_for_user +from drf_spectacular.utils import extend_schema, inline_serializer from rest_framework import mixins from rest_framework.decorators import action -from rest_framework.fields import CharField, ChoiceField, IntegerField +from rest_framework.fields import CharField from rest_framework.filters import OrderingFilter, SearchFilter from rest_framework.permissions import IsAdminUser from rest_framework.request import Request @@ -15,7 +13,6 @@ from rest_framework.serializers import ModelSerializer from rest_framework.viewsets import GenericViewSet, ModelViewSet from authentik.api.authorization import OwnerFilter, OwnerPermissions -from authentik.api.decorators import permission_required from authentik.core.api.used_by import UsedByMixin from authentik.flows.api.stages import StageSerializer from authentik.stages.authenticator_mobile.models import AuthenticatorMobileStage, MobileDevice diff --git a/authentik/stages/authenticator_mobile/migrations/0001_initial.py b/authentik/stages/authenticator_mobile/migrations/0001_initial.py index 29705238e..ae41f6357 100644 --- a/authentik/stages/authenticator_mobile/migrations/0001_initial.py +++ b/authentik/stages/authenticator_mobile/migrations/0001_initial.py @@ -1,9 +1,12 @@ -# Generated by Django 4.1.10 on 2023-07-24 18:48 +# Generated by Django 4.1.10 on 2023-07-24 21:33 import django.db.models.deletion from django.conf import settings from django.db import migrations, models +import authentik.core.models +import authentik.stages.authenticator_mobile.models + class Migration(migrations.Migration): initial = True @@ -85,4 +88,43 @@ class Migration(migrations.Migration): "verbose_name_plural": "Mobile Devices", }, ), + migrations.CreateModel( + name="MobileDeviceToken", + fields=[ + ( + "id", + models.AutoField( + auto_created=True, primary_key=True, serialize=False, verbose_name="ID" + ), + ), + ( + "expires", + models.DateTimeField(default=authentik.core.models.default_token_duration), + ), + ("expiring", models.BooleanField(default=True)), + ( + "token", + models.TextField( + default=authentik.stages.authenticator_mobile.models.default_token_key + ), + ), + ( + "device", + models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.CASCADE, + to="authentik_stages_authenticator_mobile.mobiledevice", + ), + ), + ( + "user", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL + ), + ), + ], + options={ + "abstract": False, + }, + ), ] diff --git a/authentik/stages/authenticator_mobile/models.py b/authentik/stages/authenticator_mobile/models.py index 211bbfe87..a4c2ce488 100644 --- a/authentik/stages/authenticator_mobile/models.py +++ b/authentik/stages/authenticator_mobile/models.py @@ -7,8 +7,8 @@ from django.utils.translation import gettext_lazy as _ from django.views import View from django_otp.models import Device from rest_framework.serializers import BaseSerializer, Serializer -from authentik.core.models import ExpiringModel +from authentik.core.models import ExpiringModel from authentik.core.types import UserSettingSerializer from authentik.flows.models import ConfigurableStage, FriendlyNamedStage, Stage from authentik.lib.generators import generate_id @@ -21,7 +21,7 @@ def default_token_key(): class AuthenticatorMobileStage(ConfigurableStage, FriendlyNamedStage, Stage): - """Setup Duo authenticator devices""" + """Setup Mobile authenticator devices""" @property def serializer(self) -> type[BaseSerializer]: @@ -78,8 +78,8 @@ class MobileDevice(SerializerModel, Device): verbose_name = _("Mobile Device") verbose_name_plural = _("Mobile Devices") -class MobileDeviceToken(ExpiringModel): +class MobileDeviceToken(ExpiringModel): device = models.ForeignKey(MobileDevice, on_delete=models.CASCADE, null=True) user = models.ForeignKey(get_user_model(), on_delete=models.CASCADE) token = models.TextField(default=default_token_key) diff --git a/authentik/stages/authenticator_mobile/stage.py b/authentik/stages/authenticator_mobile/stage.py index bdd4912da..2f09e344a 100644 --- a/authentik/stages/authenticator_mobile/stage.py +++ b/authentik/stages/authenticator_mobile/stage.py @@ -1,10 +1,8 @@ """Mobile stage""" from django.http import HttpResponse -from django.utils.timezone import now from rest_framework.fields import CharField -from authentik.core.api.utils import PassiveSerializer -from authentik.events.models import Event, EventAction +from authentik.core.api.utils import PassiveSerializer from authentik.flows.challenge import ( Challenge, ChallengeResponse, @@ -24,6 +22,7 @@ class AuthenticatorMobilePayloadChallenge(PassiveSerializer): s = CharField(required=False, help_text="Stage UUID") t = CharField(required=False, help_text="Initial Token") + class AuthenticatorMobileChallenge(WithUserInfoChallenge): """Mobile Challenge""" @@ -53,12 +52,14 @@ class AuthenticatorMobileStageView(ChallengeStageView): def get_challenge(self, *args, **kwargs) -> Challenge: stage: AuthenticatorMobileStage = self.executor.current_stage self.prepare() - payload = AuthenticatorMobilePayloadChallenge(data={ - # TODO: use cloud gateway? - "u": self.request.get_host(), - "s": str(stage.stage_uuid), - "t": self.executor.plan[FLOW_PLAN_MOBILE_ENROLL].token, - }) + payload = AuthenticatorMobilePayloadChallenge( + data={ + # TODO: use cloud gateway? + "u": self.request.get_host(), + "s": str(stage.stage_uuid), + "t": self.executor.plan[FLOW_PLAN_MOBILE_ENROLL].token, + } + ) payload.is_valid() return AuthenticatorMobileChallenge( data={