use more minimal payload for QR code sake
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
This commit is contained in:
parent
fc5f5ed117
commit
cb60fc2c7b
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
)
|
||||
|
||||
|
|
23
schema.yml
23
schema.yml
|
@ -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
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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>
|
||||
|
|
Reference in New Issue