move functions to device

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
This commit is contained in:
Jens Langhammer 2023-09-03 00:00:16 +02:00
parent 91c2348b8e
commit e99a660a5f
No known key found for this signature in database
5 changed files with 211 additions and 127 deletions

View File

@ -5,9 +5,15 @@ from rest_framework.filters import OrderingFilter, SearchFilter
from rest_framework.permissions import IsAdminUser from rest_framework.permissions import IsAdminUser
from rest_framework.serializers import ModelSerializer from rest_framework.serializers import ModelSerializer
from rest_framework.viewsets import GenericViewSet, ModelViewSet from rest_framework.viewsets import GenericViewSet, ModelViewSet
from drf_spectacular.utils import extend_schema, inline_serializer
from rest_framework.decorators import action
from rest_framework.fields import CharField, UUIDField
from rest_framework.request import Request
from rest_framework.response import Response
from authentik.api.authorization import OwnerFilter, OwnerPermissions from authentik.api.authorization import OwnerFilter, OwnerPermissions
from authentik.core.api.used_by import UsedByMixin from authentik.core.api.used_by import UsedByMixin
from authentik.stages.authenticator_mobile.api.auth import MobileDeviceTokenAuthentication
from authentik.stages.authenticator_mobile.models import MobileDevice from authentik.stages.authenticator_mobile.models import MobileDevice
@ -38,6 +44,69 @@ class MobileDeviceViewSet(
permission_classes = [OwnerPermissions] permission_classes = [OwnerPermissions]
filter_backends = [OwnerFilter, DjangoFilterBackend, OrderingFilter, SearchFilter] filter_backends = [OwnerFilter, DjangoFilterBackend, OrderingFilter, SearchFilter]
@extend_schema(
responses={
204: "",
},
request=inline_serializer(
"MobileDeviceSetPushKeySerializer",
{
"firebase_key": CharField(required=True),
},
),
)
@action(
methods=["POST"],
detail=True,
permission_classes=[],
authentication_classes=[MobileDeviceTokenAuthentication],
)
def set_notification_key(self):
"""Called by the phone whenever the firebase key changes and we need to update it"""
device = self.get_object()
print(self.request.user)
@action(
methods=["POST"],
detail=True,
permission_classes=[],
authentication_classes=[MobileDeviceTokenAuthentication],
)
def receive_response():
"""Get response from notification on phone"""
pass
@extend_schema(
responses={
200: inline_serializer(
"MobileDeviceEnrollmentCallbackSerializer",
{
"device_token": CharField(required=True),
"device_uuid": UUIDField(required=True)
},
),
},
request=inline_serializer(
"MobileDeviceEnrollmentSerializer",
{
# New API token (that will be rotated at some point)
# also used by the backend to sign requests to the cloud broker
# also used by the app to check the signature of incoming requests
"token": CharField(required=True),
},
),
)
@action(
methods=["POST"],
detail=True,
permission_classes=[],
authentication_classes=[MobileDeviceTokenAuthentication],
)
def enrollment_callback(self, request: Request, pk: str) -> Response:
"""Enrollment callback"""
print(request.data)
return Response(status=204)
class AdminMobileDeviceViewSet(ModelViewSet): class AdminMobileDeviceViewSet(ModelViewSet):
"""Viewset for Mobile authenticator devices (for admins)""" """Viewset for Mobile authenticator devices (for admins)"""

View File

@ -1,14 +1,8 @@
"""AuthenticatorMobileStage API Views""" """AuthenticatorMobileStage API Views"""
from drf_spectacular.utils import extend_schema, inline_serializer
from rest_framework.decorators import action
from rest_framework.fields import CharField
from rest_framework.request import Request
from rest_framework.response import Response
from rest_framework.viewsets import ModelViewSet from rest_framework.viewsets import ModelViewSet
from authentik.core.api.used_by import UsedByMixin from authentik.core.api.used_by import UsedByMixin
from authentik.flows.api.stages import StageSerializer from authentik.flows.api.stages import StageSerializer
from authentik.stages.authenticator_mobile.api.auth import MobileDeviceTokenAuthentication
from authentik.stages.authenticator_mobile.models import AuthenticatorMobileStage from authentik.stages.authenticator_mobile.models import AuthenticatorMobileStage
@ -34,30 +28,3 @@ class AuthenticatorMobileStageViewSet(UsedByMixin, ModelViewSet):
] ]
search_fields = ["name"] search_fields = ["name"]
ordering = ["name"] ordering = ["name"]
@extend_schema(
responses={
200: inline_serializer(
"MobileDeviceEnrollmentCallbackSerializer",
{
"device_token": CharField(required=True),
},
),
},
request=inline_serializer(
"MobileDeviceEnrollmentSerializer",
{
"device_token": CharField(required=True),
},
),
)
@action(
methods=["POST"],
detail=True,
permission_classes=[],
authentication_classes=[MobileDeviceTokenAuthentication],
)
def enrollment_callback(self, request: Request, pk: str) -> Response:
"""Enrollment callback"""
print(request.data)
return Response(status=204)

View File

@ -87,3 +87,5 @@ class MobileDeviceToken(ExpiringModel):
device = models.ForeignKey(MobileDevice, on_delete=models.CASCADE, null=True) device = models.ForeignKey(MobileDevice, on_delete=models.CASCADE, null=True)
user = models.ForeignKey(get_user_model(), on_delete=models.CASCADE) user = models.ForeignKey(get_user_model(), on_delete=models.CASCADE)
token = models.TextField(default=default_token_key) token = models.TextField(default=default_token_key)
firebase_token = models.TextField(blank=True)

View File

@ -10,7 +10,7 @@ from authentik.flows.challenge import (
WithUserInfoChallenge, WithUserInfoChallenge,
) )
from authentik.flows.stage import ChallengeStageView from authentik.flows.stage import ChallengeStageView
from authentik.stages.authenticator_mobile.models import AuthenticatorMobileStage, MobileDeviceToken from authentik.stages.authenticator_mobile.models import AuthenticatorMobileStage, MobileDevice, MobileDeviceToken
FLOW_PLAN_MOBILE_ENROLL = "authentik/stages/authenticator_mobile/enroll" FLOW_PLAN_MOBILE_ENROLL = "authentik/stages/authenticator_mobile/enroll"
@ -45,19 +45,23 @@ class AuthenticatorMobileStageView(ChallengeStageView):
"""Prepare the token""" """Prepare the token"""
if FLOW_PLAN_MOBILE_ENROLL in self.executor.plan.context: if FLOW_PLAN_MOBILE_ENROLL in self.executor.plan.context:
return return
device = MobileDevice.objects.create(
user=self.get_pending_user(),
stage=self.executor.current_stage,
)
token = MobileDeviceToken.objects.create( token = MobileDeviceToken.objects.create(
user=self.get_pending_user(), user=self.get_pending_user(),
device=device,
) )
self.executor.plan.context[FLOW_PLAN_MOBILE_ENROLL] = token self.executor.plan.context[FLOW_PLAN_MOBILE_ENROLL] = token
def get_challenge(self, *args, **kwargs) -> Challenge: def get_challenge(self, *args, **kwargs) -> Challenge:
stage: AuthenticatorMobileStage = self.executor.current_stage
self.prepare() self.prepare()
payload = AuthenticatorMobilePayloadChallenge( payload = AuthenticatorMobilePayloadChallenge(
data={ data={
# TODO: use cloud gateway? # TODO: use cloud gateway?
"u": self.request.build_absolute_uri("/"), "u": self.request.build_absolute_uri("/"),
"s": str(stage.stage_uuid), "s": self.executor.plan.context[FLOW_PLAN_MOBILE_ENROLL].device.pk,
"t": self.executor.plan.context[FLOW_PLAN_MOBILE_ENROLL].token, "t": self.executor.plan.context[FLOW_PLAN_MOBILE_ENROLL].token,
} }
) )

View File

@ -2157,6 +2157,123 @@ paths:
schema: schema:
$ref: '#/components/schemas/GenericError' $ref: '#/components/schemas/GenericError'
description: '' description: ''
/authenticators/mobile/{id}/enrollment_callback/:
post:
operationId: authenticators_mobile_enrollment_callback_create
description: Enrollment callback
parameters:
- in: path
name: id
schema:
type: integer
description: A unique integer value identifying this Mobile Device.
required: true
tags:
- authenticators
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/MobileDeviceEnrollmentRequest'
required: true
security:
- mobile_device_token: []
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/MobileDeviceEnrollmentCallback'
description: ''
'400':
content:
application/json:
schema:
$ref: '#/components/schemas/ValidationError'
description: ''
'403':
content:
application/json:
schema:
$ref: '#/components/schemas/GenericError'
description: ''
/authenticators/mobile/{id}/receive_response/:
post:
operationId: authenticators_mobile_receive_response_create
description: Get response from notification on phone
parameters:
- in: path
name: id
schema:
type: integer
description: A unique integer value identifying this Mobile Device.
required: true
tags:
- authenticators
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/MobileDeviceRequest'
required: true
security:
- mobile_device_token: []
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/MobileDevice'
description: ''
'400':
content:
application/json:
schema:
$ref: '#/components/schemas/ValidationError'
description: ''
'403':
content:
application/json:
schema:
$ref: '#/components/schemas/GenericError'
description: ''
/authenticators/mobile/{id}/set_notification_key/:
post:
operationId: authenticators_mobile_set_notification_key_create
description: Called by the phone whenever the firebase key changes and we need
to update it
parameters:
- in: path
name: id
schema:
type: integer
description: A unique integer value identifying this Mobile Device.
required: true
tags:
- authenticators
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/MobileDeviceSetPushKeyRequest'
required: true
security:
- mobile_device_token: []
responses:
'204':
description: No response body
'400':
content:
application/json:
schema:
$ref: '#/components/schemas/ValidationError'
description: ''
'403':
content:
application/json:
schema:
$ref: '#/components/schemas/GenericError'
description: ''
/authenticators/mobile/{id}/used_by/: /authenticators/mobile/{id}/used_by/:
get: get:
operationId: authenticators_mobile_used_by_list operationId: authenticators_mobile_used_by_list
@ -23421,47 +23538,6 @@ paths:
schema: schema:
$ref: '#/components/schemas/GenericError' $ref: '#/components/schemas/GenericError'
description: '' description: ''
/stages/authenticator/mobile/{stage_uuid}/enrollment_callback/:
post:
operationId: stages_authenticator_mobile_enrollment_callback_create
description: Enrollment callback
parameters:
- in: path
name: stage_uuid
schema:
type: string
format: uuid
description: A UUID string identifying this Mobile Authenticator Setup Stage.
required: true
tags:
- stages
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/MobileDeviceEnrollmentRequest'
required: true
security:
- mobile_device_token: []
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/MobileDeviceEnrollmentCallback'
description: ''
'400':
content:
application/json:
schema:
$ref: '#/components/schemas/ValidationError'
description: ''
'403':
content:
application/json:
schema:
$ref: '#/components/schemas/GenericError'
description: ''
/stages/authenticator/mobile/{stage_uuid}/used_by/: /stages/authenticator/mobile/{stage_uuid}/used_by/:
get: get:
operationId: stages_authenticator_mobile_used_by_list operationId: stages_authenticator_mobile_used_by_list
@ -35133,16 +35209,20 @@ components:
properties: properties:
device_token: device_token:
type: string type: string
device_uuid:
type: string
format: uuid
required: required:
- device_token - device_token
- device_uuid
MobileDeviceEnrollmentRequest: MobileDeviceEnrollmentRequest:
type: object type: object
properties: properties:
device_token: token:
type: string type: string
minLength: 1 minLength: 1
required: required:
- device_token - token
MobileDeviceRequest: MobileDeviceRequest:
type: object type: object
description: Serializer for Mobile authenticator devices description: Serializer for Mobile authenticator devices
@ -35154,6 +35234,14 @@ components:
maxLength: 64 maxLength: 64
required: required:
- name - name
MobileDeviceSetPushKeyRequest:
type: object
properties:
firebase_key:
type: string
minLength: 1
required:
- firebase_key
ModelEnum: ModelEnum:
enum: enum:
- authentik_crypto.certificatekeypair - authentik_crypto.certificatekeypair
@ -36361,30 +36449,7 @@ components:
type: object type: object
properties: properties:
pagination: pagination:
type: object $ref: '#/components/schemas/Pagination'
properties:
next:
type: number
previous:
type: number
count:
type: number
current:
type: number
total_pages:
type: number
start_index:
type: number
end_index:
type: number
required:
- next
- previous
- count
- current
- total_pages
- start_index
- end_index
results: results:
type: array type: array
items: items:
@ -36792,30 +36857,7 @@ components:
type: object type: object
properties: properties:
pagination: pagination:
type: object $ref: '#/components/schemas/Pagination'
properties:
next:
type: number
previous:
type: number
count:
type: number
current:
type: number
total_pages:
type: number
start_index:
type: number
end_index:
type: number
required:
- next
- previous
- count
- current
- total_pages
- start_index
- end_index
results: results:
type: array type: array
items: items: