stages/authenticator_duo: revamp duo enroll status API
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> #3288
This commit is contained in:
parent
2858682866
commit
54c16129ea
|
@ -1,10 +1,16 @@
|
|||
"""AuthenticatorDuoStage API Views"""
|
||||
from django_filters.rest_framework.backends import DjangoFilterBackend
|
||||
from drf_spectacular.types import OpenApiTypes
|
||||
from drf_spectacular.utils import OpenApiParameter, OpenApiResponse, extend_schema
|
||||
from drf_spectacular.utils import (
|
||||
OpenApiParameter,
|
||||
OpenApiResponse,
|
||||
extend_schema,
|
||||
inline_serializer,
|
||||
)
|
||||
from guardian.shortcuts import get_objects_for_user
|
||||
from rest_framework import mixins
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.fields import ChoiceField
|
||||
from rest_framework.filters import OrderingFilter, SearchFilter
|
||||
from rest_framework.permissions import IsAdminUser
|
||||
from rest_framework.request import Request
|
||||
|
@ -57,8 +63,18 @@ class AuthenticatorDuoStageViewSet(UsedByMixin, ModelViewSet):
|
|||
@extend_schema(
|
||||
request=OpenApiTypes.NONE,
|
||||
responses={
|
||||
204: OpenApiResponse(description="Enrollment successful"),
|
||||
420: OpenApiResponse(description="Enrollment pending/failed"),
|
||||
200: inline_serializer(
|
||||
"DuoDeviceEnrollmentStatusSerializer",
|
||||
{
|
||||
"duo_response": ChoiceField(
|
||||
(
|
||||
("success", "Success"),
|
||||
("waiting", "Waiting"),
|
||||
("invalid", "Invalid"),
|
||||
)
|
||||
)
|
||||
},
|
||||
),
|
||||
},
|
||||
)
|
||||
@action(methods=["POST"], detail=True, permission_classes=[])
|
||||
|
@ -70,11 +86,9 @@ class AuthenticatorDuoStageViewSet(UsedByMixin, ModelViewSet):
|
|||
user_id = self.request.session.get(SESSION_KEY_DUO_USER_ID)
|
||||
activation_code = self.request.session.get(SESSION_KEY_DUO_ACTIVATION_CODE)
|
||||
if not user_id or not activation_code:
|
||||
return Response(status=420)
|
||||
return Response(status=400)
|
||||
status = client.enroll_status(user_id, activation_code)
|
||||
if status == "success":
|
||||
return Response(status=204)
|
||||
return Response(status=420)
|
||||
return Response({"duo_response": status})
|
||||
|
||||
@permission_required(
|
||||
"", ["authentik_stages_authenticator_duo.add_duodevice", "authentik_core.view_user"]
|
||||
|
|
|
@ -94,5 +94,5 @@ class AuthenticatorDuoStageView(ChallengeStageView):
|
|||
return self.executor.stage_ok()
|
||||
|
||||
def cleanup(self):
|
||||
self.request.session.pop(SESSION_KEY_DUO_USER_ID)
|
||||
self.request.session.pop(SESSION_KEY_DUO_ACTIVATION_CODE)
|
||||
self.request.session.pop(SESSION_KEY_DUO_USER_ID, None)
|
||||
self.request.session.pop(SESSION_KEY_DUO_ACTIVATION_CODE, None)
|
||||
|
|
23
schema.yml
23
schema.yml
|
@ -15076,10 +15076,12 @@ paths:
|
|||
security:
|
||||
- authentik: []
|
||||
responses:
|
||||
'204':
|
||||
description: Enrollment successful
|
||||
'420':
|
||||
description: Enrollment pending/failed
|
||||
'200':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/DuoDeviceEnrollmentStatus'
|
||||
description: ''
|
||||
'400':
|
||||
$ref: '#/components/schemas/ValidationError'
|
||||
'403':
|
||||
|
@ -21877,6 +21879,13 @@ components:
|
|||
required:
|
||||
- name
|
||||
- pk
|
||||
DuoDeviceEnrollmentStatus:
|
||||
type: object
|
||||
properties:
|
||||
duo_response:
|
||||
$ref: '#/components/schemas/DuoResponseEnum'
|
||||
required:
|
||||
- duo_response
|
||||
DuoDeviceRequest:
|
||||
type: object
|
||||
description: Serializer for Duo authenticator devices
|
||||
|
@ -21888,6 +21897,12 @@ components:
|
|||
maxLength: 64
|
||||
required:
|
||||
- name
|
||||
DuoResponseEnum:
|
||||
enum:
|
||||
- success
|
||||
- waiting
|
||||
- invalid
|
||||
type: string
|
||||
EmailChallenge:
|
||||
type: object
|
||||
description: Email challenge
|
||||
|
|
|
@ -21,6 +21,7 @@ import PFBase from "@patternfly/patternfly/patternfly-base.css";
|
|||
import {
|
||||
AuthenticatorDuoChallenge,
|
||||
AuthenticatorDuoChallengeResponseRequest,
|
||||
DuoResponseEnum,
|
||||
StagesApi,
|
||||
} from "@goauthentik/api";
|
||||
|
||||
|
@ -35,23 +36,29 @@ export class AuthenticatorDuoStage extends BaseStage<
|
|||
|
||||
firstUpdated(): void {
|
||||
const i = setInterval(() => {
|
||||
this.checkEnrollStatus().then(() => {
|
||||
this.checkEnrollStatus().then((shouldStop) => {
|
||||
if (shouldStop) {
|
||||
clearInterval(i);
|
||||
}
|
||||
});
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
checkEnrollStatus(): Promise<void> {
|
||||
return new StagesApi(DEFAULT_CONFIG)
|
||||
.stagesAuthenticatorDuoEnrollmentStatusCreate({
|
||||
async checkEnrollStatus(): Promise<boolean> {
|
||||
const status = await new StagesApi(
|
||||
DEFAULT_CONFIG,
|
||||
).stagesAuthenticatorDuoEnrollmentStatusCreate({
|
||||
stageUuid: this.challenge?.stageUuid || "",
|
||||
})
|
||||
.then(() => {
|
||||
this.host?.submit({});
|
||||
})
|
||||
.catch(() => {
|
||||
console.debug("authentik/flows/duo: Waiting for auth status");
|
||||
});
|
||||
console.debug(`authentik/flows/duo: Enrollment status: ${status.duoResponse}`);
|
||||
switch (status.duoResponse) {
|
||||
case DuoResponseEnum.Success:
|
||||
this.host?.submit({});
|
||||
return true;
|
||||
case DuoResponseEnum.Waiting:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
render(): TemplateResult {
|
||||
|
|
Reference in a new issue