fix stuff

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
This commit is contained in:
Jens Langhammer 2023-07-25 14:18:15 +02:00
parent 4813bd033e
commit 130ec2128d
No known key found for this signature in database
9 changed files with 135 additions and 54 deletions

View File

@ -130,7 +130,10 @@ SPECTACULAR_SETTINGS = {
"CONTACT": { "CONTACT": {
"email": "hello@goauthentik.io", "email": "hello@goauthentik.io",
}, },
"AUTHENTICATION_WHITELIST": ["authentik.api.authentication.TokenAuthentication"], "AUTHENTICATION_WHITELIST": [
"authentik.stages.authenticator_mobile.api.auth.MobileDeviceTokenAuthentication",
"authentik.api.authentication.TokenAuthentication",
],
"LICENSE": { "LICENSE": {
"name": "MIT", "name": "MIT",
"url": "https://github.com/goauthentik/authentik/blob/main/LICENSE", "url": "https://github.com/goauthentik/authentik/blob/main/LICENSE",

View File

@ -0,0 +1,40 @@
"""Mobile device token authentication"""
from typing import Any
from drf_spectacular.extensions import OpenApiAuthenticationExtension
from rest_framework.authentication import BaseAuthentication, get_authorization_header
from rest_framework.request import Request
from authentik.api.authentication import validate_auth
from authentik.core.models import User
from authentik.stages.authenticator_mobile.models import MobileDeviceToken
class MobileDeviceTokenAuthentication(BaseAuthentication):
"""Mobile device token authentication"""
def authenticate(self, request: Request) -> tuple[User, Any] | None:
"""Token-based authentication using HTTP Bearer authentication"""
auth = get_authorization_header(request)
raw_token = validate_auth(auth)
device_token: MobileDeviceToken = MobileDeviceToken.objects.filter(token=raw_token).first()
if not device_token:
return None
return (device_token.user, None)
class TokenSchema(OpenApiAuthenticationExtension):
"""Auth schema"""
target_class = MobileDeviceTokenAuthentication
name = "mobile_device_token"
def get_security_definition(self, auto_schema):
"""Auth schema"""
return {
"type": "apiKey",
"in": "header",
"name": "Authorization",
"scheme": "bearer",
}

View File

@ -1,60 +1,14 @@
"""AuthenticatorMobileStage API Views""" """AuthenticatorMobileStage API Views"""
from django_filters.rest_framework.backends import DjangoFilterBackend from django_filters.rest_framework.backends import DjangoFilterBackend
from drf_spectacular.types import OpenApiTypes
from drf_spectacular.utils import extend_schema, inline_serializer
from rest_framework import mixins from rest_framework import mixins
from rest_framework.decorators import action
from rest_framework.fields import CharField
from rest_framework.filters import OrderingFilter, SearchFilter from rest_framework.filters import OrderingFilter, SearchFilter
from rest_framework.permissions import IsAdminUser from rest_framework.permissions import IsAdminUser
from rest_framework.request import Request
from rest_framework.response import Response
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 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.flows.api.stages import StageSerializer from authentik.stages.authenticator_mobile.models import MobileDevice
from authentik.stages.authenticator_mobile.models import AuthenticatorMobileStage, MobileDevice
class AuthenticatorMobileStageSerializer(StageSerializer):
"""AuthenticatorMobileStage Serializer"""
class Meta:
model = AuthenticatorMobileStage
fields = StageSerializer.Meta.fields + [
"configure_flow",
"friendly_name",
]
class AuthenticatorMobileStageViewSet(UsedByMixin, ModelViewSet):
"""AuthenticatorMobileStage Viewset"""
queryset = AuthenticatorMobileStage.objects.all()
serializer_class = AuthenticatorMobileStageSerializer
filterset_fields = [
"name",
"configure_flow",
]
search_fields = ["name"]
ordering = ["name"]
@extend_schema(
request=OpenApiTypes.NONE,
responses={
200: inline_serializer(
"MobileDeviceEnrollmentCallbackSerializer",
{
"device_token": CharField(required=True),
},
),
},
)
@action(methods=["POST"], detail=True, permission_classes=[])
def enrollment_callback(self, request: Request, pk: str) -> Response:
"""Enrollment callback"""
class MobileDeviceSerializer(ModelSerializer): class MobileDeviceSerializer(ModelSerializer):

View File

@ -0,0 +1,63 @@
"""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 authentik.core.api.used_by import UsedByMixin
from authentik.flows.api.stages import StageSerializer
from authentik.stages.authenticator_mobile.api.auth import MobileDeviceTokenAuthentication
from authentik.stages.authenticator_mobile.models import AuthenticatorMobileStage
class AuthenticatorMobileStageSerializer(StageSerializer):
"""AuthenticatorMobileStage Serializer"""
class Meta:
model = AuthenticatorMobileStage
fields = StageSerializer.Meta.fields + [
"configure_flow",
"friendly_name",
]
class AuthenticatorMobileStageViewSet(UsedByMixin, ModelViewSet):
"""AuthenticatorMobileStage Viewset"""
queryset = AuthenticatorMobileStage.objects.all()
serializer_class = AuthenticatorMobileStageSerializer
filterset_fields = [
"name",
"configure_flow",
]
search_fields = ["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

@ -25,7 +25,9 @@ class AuthenticatorMobileStage(ConfigurableStage, FriendlyNamedStage, Stage):
@property @property
def serializer(self) -> type[BaseSerializer]: def serializer(self) -> type[BaseSerializer]:
from authentik.stages.authenticator_mobile.api import AuthenticatorMobileStageSerializer from authentik.stages.authenticator_mobile.api.stage import (
AuthenticatorMobileStageSerializer,
)
return AuthenticatorMobileStageSerializer return AuthenticatorMobileStageSerializer
@ -67,7 +69,7 @@ class MobileDevice(SerializerModel, Device):
@property @property
def serializer(self) -> Serializer: def serializer(self) -> Serializer:
from authentik.stages.authenticator_mobile.api import MobileDeviceSerializer from authentik.stages.authenticator_mobile.api.device import MobileDeviceSerializer
return MobileDeviceSerializer return MobileDeviceSerializer

View File

@ -56,7 +56,7 @@ class AuthenticatorMobileStageView(ChallengeStageView):
payload = AuthenticatorMobilePayloadChallenge( payload = AuthenticatorMobilePayloadChallenge(
data={ data={
# TODO: use cloud gateway? # TODO: use cloud gateway?
"u": self.request.get_host(), "u": self.request.build_absolute_uri("/"),
"s": str(stage.stage_uuid), "s": str(stage.stage_uuid),
"t": self.executor.plan.context[FLOW_PLAN_MOBILE_ENROLL].token, "t": self.executor.plan.context[FLOW_PLAN_MOBILE_ENROLL].token,
} }

View File

@ -1,9 +1,9 @@
"""API URLs""" """API URLs"""
from authentik.stages.authenticator_mobile.api import ( from authentik.stages.authenticator_mobile.api.device import (
AdminMobileDeviceViewSet, AdminMobileDeviceViewSet,
AuthenticatorMobileStageViewSet,
MobileDeviceViewSet, MobileDeviceViewSet,
) )
from authentik.stages.authenticator_mobile.api.stage import AuthenticatorMobileStageViewSet
api_urlpatterns = [ api_urlpatterns = [
("authenticators/mobile", MobileDeviceViewSet), ("authenticators/mobile", MobileDeviceViewSet),

View File

@ -22611,8 +22611,14 @@ paths:
required: true required: true
tags: tags:
- stages - stages
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/MobileDeviceEnrollmentRequest'
required: true
security: security:
- authentik: [] - mobile_device_token: []
responses: responses:
'200': '200':
content: content:
@ -34141,6 +34147,14 @@ components:
type: string type: string
required: required:
- device_token - device_token
MobileDeviceEnrollmentRequest:
type: object
properties:
device_token:
type: string
minLength: 1
required:
- device_token
MobileDeviceRequest: MobileDeviceRequest:
type: object type: object
description: Serializer for Mobile authenticator devices description: Serializer for Mobile authenticator devices
@ -43692,5 +43706,10 @@ components:
in: header in: header
name: Authorization name: Authorization
scheme: bearer scheme: bearer
mobile_device_token:
type: apiKey
in: header
name: Authorization
scheme: bearer
servers: servers:
- url: /api/v3/ - url: /api/v3/