use more minimal payload for QR code sake

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
This commit is contained in:
Jens Langhammer 2023-07-24 23:23:01 +02:00
parent fc5f5ed117
commit cb60fc2c7b
No known key found for this signature in database
5 changed files with 62 additions and 14 deletions

View File

@ -7,12 +7,19 @@ 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.types import UserSettingSerializer
from authentik.flows.models import ConfigurableStage, FriendlyNamedStage, Stage
from authentik.lib.generators import generate_id
from authentik.lib.models import SerializerModel
def default_token_key():
"""Default token key"""
return generate_id(40)
class AuthenticatorMobileStage(ConfigurableStage, FriendlyNamedStage, Stage):
"""Setup Duo authenticator devices"""
@ -70,3 +77,9 @@ class MobileDevice(SerializerModel, Device):
class Meta:
verbose_name = _("Mobile Device")
verbose_name_plural = _("Mobile Devices")
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)

View File

@ -2,6 +2,7 @@
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.flows.challenge import (
@ -11,16 +12,22 @@ from authentik.flows.challenge import (
WithUserInfoChallenge,
)
from authentik.flows.stage import ChallengeStageView
from authentik.stages.authenticator_mobile.models import AuthenticatorMobileStage
from authentik.stages.authenticator_mobile.models import AuthenticatorMobileStage, MobileDeviceToken
SESSION_KEY_MOBILE_ENROLL = "authentik/stages/authenticator_mobile/enroll"
FLOW_PLAN_MOBILE_ENROLL = "authentik/stages/authenticator_mobile/enroll"
class AuthenticatorMobilePayloadChallenge(PassiveSerializer):
"""Payload within the QR code given to the mobile app, hence the short variable names"""
u = CharField(required=False, help_text="Server URL")
s = CharField(required=False, help_text="Stage UUID")
t = CharField(required=False, help_text="Initial Token")
class AuthenticatorMobileChallenge(WithUserInfoChallenge):
"""Mobile Challenge"""
authentik_url = CharField(required=True)
stage_uuid = CharField(required=True)
payload = AuthenticatorMobilePayloadChallenge(required=True)
component = CharField(default="ak-stage-authenticator-mobile")
@ -35,13 +42,28 @@ class AuthenticatorMobileStageView(ChallengeStageView):
response_class = AuthenticatorMobileChallengeResponse
def prepare(self):
if FLOW_PLAN_MOBILE_ENROLL in self.executor.plan.context:
return
token = MobileDeviceToken.objects.create(
user=self.get_pending_user(),
)
self.executor.plan.context[FLOW_PLAN_MOBILE_ENROLL] = token
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.is_valid()
return AuthenticatorMobileChallenge(
data={
"type": ChallengeTypes.NATIVE.value,
"authentik_url": self.request.get_host(),
"stage_uuid": str(stage.stage_uuid),
"payload": payload.validated_data,
}
)

View File

@ -30183,15 +30183,12 @@ components:
type: string
pending_user_avatar:
type: string
authentik_url:
type: string
stage_uuid:
type: string
payload:
$ref: '#/components/schemas/AuthenticatorMobilePayloadChallenge'
required:
- authentik_url
- payload
- pending_user
- pending_user_avatar
- stage_uuid
- type
AuthenticatorMobileChallengeResponseRequest:
type: object
@ -30201,6 +30198,20 @@ components:
type: string
minLength: 1
default: ak-stage-authenticator-mobile
AuthenticatorMobilePayloadChallenge:
type: object
description: Payload within the QR code given to the mobile app, hence the short
variable names
properties:
u:
type: string
description: Server URL
s:
type: string
description: Stage UUID
t:
type: string
description: Initial Token
AuthenticatorMobileStage:
type: object
description: AuthenticatorMobileStage Serializer

View File

@ -338,7 +338,9 @@ export class FlowExecutor extends Interface implements StageHost {
.challenge=${this.challenge}
></ak-stage-authenticator-duo>`;
case "ak-stage-authenticator-mobile":
await import("@goauthentik/flow/stages/authenticator_mobile/AuthenticatorMobileStage");
await import(
"@goauthentik/flow/stages/authenticator_mobile/AuthenticatorMobileStage"
);
return html`<ak-stage-authenticator-mobile
.host=${this as StageHost}
.challenge=${this.challenge}

View File

@ -70,7 +70,7 @@ export class AuthenticatorMobileStage extends BaseStage<
</div>
</ak-form-static>
<div class="qr-container">
<qr-code data="${JSON.stringify(this.challenge)}"></qr-code>
<qr-code data="${JSON.stringify(this.challenge.payload)}"></qr-code>
</div>
</form>
</div>