Signed-off-by: Jens Langhammer <jens@goauthentik.io>
This commit is contained in:
Jens Langhammer 2023-09-04 18:04:46 +02:00
parent f4a18d1778
commit 14ab9a9f1b
No known key found for this signature in database
3 changed files with 44 additions and 22 deletions

View File

@ -1,6 +1,6 @@
"""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.utils import extend_schema, inline_serializer, OpenApiResponse from drf_spectacular.utils import OpenApiResponse, extend_schema, inline_serializer
from rest_framework import mixins from rest_framework import mixins
from rest_framework.decorators import action from rest_framework.decorators import action
from rest_framework.fields import CharField, ChoiceField from rest_framework.fields import CharField, ChoiceField
@ -75,7 +75,7 @@ class MobileDeviceViewSet(
methods=["POST"], methods=["POST"],
detail=True, detail=True,
permission_classes=[], permission_classes=[],
filter_backends = [], filter_backends=[],
authentication_classes=[MobileDeviceTokenAuthentication], authentication_classes=[MobileDeviceTokenAuthentication],
) )
def enrollment_callback(self, request: Request, pk: str) -> Response: def enrollment_callback(self, request: Request, pk: str) -> Response:
@ -115,11 +115,13 @@ class MobileDeviceViewSet(
), ),
}, },
) )
@action(methods=["POST"], @action(
methods=["POST"],
detail=True, detail=True,
permission_classes=[], permission_classes=[],
filter_backends = [], filter_backends=[],
authentication_classes=[MobileDeviceTokenAuthentication],) authentication_classes=[MobileDeviceTokenAuthentication],
)
def enrollment_status(self, request: Request, pk: str) -> Response: def enrollment_status(self, request: Request, pk: str) -> Response:
"""Check device enrollment status""" """Check device enrollment status"""
device: MobileDevice = self.get_object() device: MobileDevice = self.get_object()

View File

@ -1,39 +1,42 @@
"""Mobile authenticator stage""" """Mobile authenticator stage"""
from typing import Optional from typing import Optional
from uuid import uuid4 from uuid import uuid4
from django.contrib.auth import get_user_model
from django.db import models
from django.http import HttpRequest
from django.utils.translation import gettext as __
from django.utils.translation import gettext_lazy as _
from django.views import View
from django_otp.models import Device
from firebase_admin import credentials, initialize_app
from firebase_admin.exceptions import FirebaseError
from firebase_admin.messaging import ( from firebase_admin.messaging import (
Message,
send,
AndroidConfig, AndroidConfig,
AndroidNotification, AndroidNotification,
APNSConfig, APNSConfig,
APNSPayload, APNSPayload,
Notification,
Aps, Aps,
Message,
Notification,
send,
) )
from firebase_admin.exceptions import FirebaseError
from structlog.stdlib import get_logger
from django.contrib.auth import get_user_model
from django.db import models
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 rest_framework.serializers import BaseSerializer, Serializer
from structlog.stdlib import get_logger
from authentik.core.models import ExpiringModel from authentik.core.models import ExpiringModel
from authentik.core.types import UserSettingSerializer from authentik.core.types import UserSettingSerializer
from authentik.flows.models import ConfigurableStage, FriendlyNamedStage, Stage from authentik.flows.models import ConfigurableStage, FriendlyNamedStage, Stage
from authentik.lib.generators import generate_id from authentik.lib.generators import generate_id
from authentik.lib.models import SerializerModel from authentik.lib.models import SerializerModel
from authentik.tenants.utils import DEFAULT_TENANT
from firebase_admin import initialize_app
from firebase_admin import credentials
cred = credentials.Certificate("firebase.json") cred = credentials.Certificate("firebase.json")
initialize_app(cred) initialize_app(cred)
LOGGER = get_logger() LOGGER = get_logger()
def default_token_key(): def default_token_key():
"""Default token key""" """Default token key"""
return generate_id(40) return generate_id(40)
@ -95,11 +98,23 @@ class MobileDevice(SerializerModel, Device):
return MobileDeviceSerializer return MobileDeviceSerializer
def send_message(self, **context): def send_message(self, request: Optional[HttpRequest], **context):
"""Send mobile message"""
branding = DEFAULT_TENANT.branding_title
domain = ""
if request:
branding = request.tenant.branding_title
domain = request.get_host()
message = Message( message = Message(
notification=Notification( notification=Notification(
title="$GOOG up 1.43% on the day", title=__("%(brand)s authentication request" % {"brand": branding}),
body="$GOOG gained 11.80 points to close at 835.67, up 1.43% on the day.", body=__(
"%(user)s is attempting to log in to %(domain)s"
% {
"user": self.user.username,
"domain": domain,
}
),
), ),
android=AndroidConfig( android=AndroidConfig(
priority="normal", priority="normal",

View File

@ -142,7 +142,12 @@ class AuthenticatorValidationChallengeResponse(ChallengeResponse):
def validate(self, attrs: dict): def validate(self, attrs: dict):
# Checking if the given data is from a valid device class is done above # Checking if the given data is from a valid device class is done above
# Here we only check if the any data was sent at all # Here we only check if the any data was sent at all
if "code" not in attrs and "webauthn" not in attrs and "duo" not in attrs and "mobile" not in attrs: if (
"code" not in attrs
and "webauthn" not in attrs
and "duo" not in attrs
and "mobile" not in attrs
):
raise ValidationError("Empty response") raise ValidationError("Empty response")
self.stage.executor.plan.context.setdefault(PLAN_CONTEXT_METHOD, "auth_mfa") self.stage.executor.plan.context.setdefault(PLAN_CONTEXT_METHOD, "auth_mfa")
self.stage.executor.plan.context.setdefault(PLAN_CONTEXT_METHOD_ARGS, {}) self.stage.executor.plan.context.setdefault(PLAN_CONTEXT_METHOD_ARGS, {})