stages/authenticator_duo: add API to "import" devices from duo
closes #1371 Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
This commit is contained in:
parent
5fd4f56fa2
commit
7dfbcdbb81
|
@ -31,7 +31,7 @@ VALIDATION_ERROR = build_object_type(
|
|||
"non_field_errors": build_array_type(build_standard_type(OpenApiTypes.STR)),
|
||||
"code": build_standard_type(OpenApiTypes.STR),
|
||||
},
|
||||
required=["detail"],
|
||||
required=[],
|
||||
additionalProperties={},
|
||||
)
|
||||
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
"""AuthenticatorDuoStage API Views"""
|
||||
from django_filters.rest_framework.backends import DjangoFilterBackend
|
||||
from drf_spectacular.types import OpenApiTypes
|
||||
from drf_spectacular.utils import OpenApiResponse, extend_schema
|
||||
from drf_spectacular.utils import OpenApiParameter, OpenApiResponse, extend_schema
|
||||
from guardian.shortcuts import get_objects_for_user
|
||||
from rest_framework import mixins
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.filters import OrderingFilter, SearchFilter
|
||||
|
@ -12,6 +13,7 @@ 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_duo.models import AuthenticatorDuoStage, DuoDevice
|
||||
|
@ -71,6 +73,43 @@ class AuthenticatorDuoStageViewSet(UsedByMixin, ModelViewSet):
|
|||
return Response(status=204)
|
||||
return Response(status=420)
|
||||
|
||||
@permission_required(
|
||||
"", ["authentik_stages_authenticator_duo.add_duodevice", "authentik_core.view_user"]
|
||||
)
|
||||
@extend_schema(
|
||||
parameters=[
|
||||
OpenApiParameter(
|
||||
name="duo_user_id", type=OpenApiTypes.STR, location=OpenApiParameter.QUERY
|
||||
),
|
||||
OpenApiParameter(
|
||||
name="username", type=OpenApiTypes.STR, location=OpenApiParameter.QUERY
|
||||
),
|
||||
],
|
||||
responses={
|
||||
204: OpenApiResponse(description="Enrollment successful"),
|
||||
400: OpenApiResponse(description="Device exists already"),
|
||||
},
|
||||
)
|
||||
@action(methods=["POST"], detail=True)
|
||||
# pylint: disable=invalid-name,unused-argument
|
||||
def import_devices(self, request: Request, pk: str) -> Response:
|
||||
"""Import duo devices into authentik"""
|
||||
stage: AuthenticatorDuoStage = self.get_object()
|
||||
users = get_objects_for_user(request.user, "authentik_core.view_user").filter(
|
||||
username=request.query_params.get("username", "")
|
||||
)
|
||||
if not users.exists():
|
||||
return Response(data={"non_field_errors": ["user does not exist"]}, status=400)
|
||||
devices = DuoDevice.objects.filter(
|
||||
duo_user_id=request.query_params.get("duo_user_id"), user=users.first(), stage=stage
|
||||
)
|
||||
if devices.exists():
|
||||
return Response(data={"non_field_errors": ["device exists already"]}, status=400)
|
||||
DuoDevice.objects.create(
|
||||
duo_user_id=request.query_params.get("duo_user_id"), user=users.first(), stage=stage
|
||||
)
|
||||
return Response(status=204)
|
||||
|
||||
|
||||
class DuoDeviceSerializer(ModelSerializer):
|
||||
"""Serializer for Duo authenticator devices"""
|
||||
|
|
39
schema.yml
39
schema.yml
|
@ -13585,6 +13585,43 @@ paths:
|
|||
$ref: '#/components/schemas/ValidationError'
|
||||
'403':
|
||||
$ref: '#/components/schemas/GenericError'
|
||||
/stages/authenticator/duo/{stage_uuid}/import_devices/:
|
||||
post:
|
||||
operationId: stages_authenticator_duo_import_devices_create
|
||||
description: Import duo devices into authentik
|
||||
parameters:
|
||||
- in: query
|
||||
name: duo_user_id
|
||||
schema:
|
||||
type: string
|
||||
- in: path
|
||||
name: stage_uuid
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
description: A UUID string identifying this Duo Authenticator Setup Stage.
|
||||
required: true
|
||||
- in: query
|
||||
name: username
|
||||
schema:
|
||||
type: string
|
||||
tags:
|
||||
- stages
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/AuthenticatorDuoStageRequest'
|
||||
required: true
|
||||
security:
|
||||
- authentik: []
|
||||
responses:
|
||||
'204':
|
||||
description: Enrollment successful
|
||||
'400':
|
||||
description: Device exists already
|
||||
'403':
|
||||
$ref: '#/components/schemas/GenericError'
|
||||
/stages/authenticator/duo/{stage_uuid}/used_by/:
|
||||
get:
|
||||
operationId: stages_authenticator_duo_used_by_list
|
||||
|
@ -29004,8 +29041,6 @@ components:
|
|||
code:
|
||||
type: string
|
||||
additionalProperties: {}
|
||||
required:
|
||||
- detail
|
||||
Version:
|
||||
type: object
|
||||
description: Get running and latest version.
|
||||
|
|
|
@ -9,3 +9,20 @@ Go to Applications, click on Protect an Application and search for "Auth API". C
|
|||
Copy all of the integration key, secret key and API hostname, and paste them in the Stage form.
|
||||
|
||||
Devices created reference the stage they were created with, since the API credentials are needed to authenticate. This also means when the stage is deleted, all devices are removed.
|
||||
|
||||
## Importing users
|
||||
|
||||
:::info
|
||||
Due to the way the Duo API works, authentik cannot automatically import existing Duo users.
|
||||
:::
|
||||
|
||||
:::info
|
||||
This API requires version 2021.10.1 or later
|
||||
:::
|
||||
|
||||
You can call the `/api/v3/stages/authenticator/duo/{stage_uuid}/import_devices/` endpoint ([see here](https://goauthentik.io/api/#post-/stages/authenticator/duo/-stage_uuid-/import_devices/)) using the following parameters:
|
||||
|
||||
- `duo_user_id`: The Duo User's ID. This can be found in the Duo Admin Portal, navigating to the user list and clicking on a single user. Their ID is shown in th URL.
|
||||
- `username`: The authentik user's username to assign the device to.
|
||||
|
||||
Additionally, you need to pass `stage_uuid` which is the `authenticator_duo` stage, in which you entered your API credentials.
|
||||
|
|
Reference in a new issue