authentik.stages.authenticator_validate.models

Authenticator Validation Stage

  1"""Authenticator Validation Stage"""
  2
  3from django.contrib.postgres.fields.array import ArrayField
  4from django.db import models
  5from django.utils.translation import gettext_lazy as _
  6from django.views import View
  7from rest_framework.serializers import BaseSerializer
  8
  9from authentik.flows.models import NotConfiguredAction, Stage
 10from authentik.lib.utils.time import timedelta_string_validator
 11from authentik.stages.authenticator_webauthn.models import UserVerification, WebAuthnHint
 12
 13
 14class DeviceClasses(models.TextChoices):
 15    """Device classes this stage can validate"""
 16
 17    # device class must match Device's class name so StaticDevice -> static
 18    STATIC = "static", _("Static")
 19    TOTP = "totp", _("TOTP")
 20    WEBAUTHN = "webauthn", _("WebAuthn")
 21    DUO = "duo", _("Duo")
 22    SMS = "sms", _("SMS")
 23    EMAIL = "email", _("Email")
 24
 25    @staticmethod
 26    def from_model_label(model_label: str) -> DeviceClasses:
 27        return getattr(
 28            DeviceClasses, model_label.rsplit(".", maxsplit=1)[-1][: -len("device")].upper()
 29        )
 30
 31
 32def default_device_classes() -> list:
 33    """By default, accept all device classes"""
 34    return [
 35        DeviceClasses.STATIC,
 36        DeviceClasses.TOTP,
 37        DeviceClasses.WEBAUTHN,
 38        DeviceClasses.DUO,
 39        DeviceClasses.SMS,
 40        DeviceClasses.EMAIL,
 41    ]
 42
 43
 44class AuthenticatorValidateStage(Stage):
 45    """Validate user's configured Multi Factor Authentication."""
 46
 47    not_configured_action = models.TextField(
 48        choices=NotConfiguredAction.choices, default=NotConfiguredAction.SKIP
 49    )
 50
 51    configuration_stages = models.ManyToManyField(
 52        Stage,
 53        blank=True,
 54        default=None,
 55        related_name="+",
 56        help_text=_(
 57            "Stages used to configure Authenticator when user doesn't have any compatible "
 58            "devices. After this configuration Stage passes, the user is not prompted again."
 59        ),
 60    )
 61
 62    device_classes = ArrayField(
 63        models.TextField(choices=DeviceClasses.choices),
 64        help_text=_("Device classes which can be used to authenticate"),
 65        default=default_device_classes,
 66    )
 67
 68    last_auth_threshold = models.TextField(
 69        default="seconds=0",
 70        validators=[timedelta_string_validator],
 71        help_text=_(
 72            "If any of the user's device has been used within this threshold, this "
 73            "stage will be skipped"
 74        ),
 75    )
 76
 77    webauthn_user_verification = models.TextField(
 78        help_text=_("Enforce user verification for WebAuthn devices."),
 79        choices=UserVerification.choices,
 80        default=UserVerification.PREFERRED,
 81    )
 82    webauthn_hints = ArrayField(
 83        models.TextField(choices=WebAuthnHint.choices),
 84        default=list,
 85        blank=True,
 86    )
 87    webauthn_allowed_device_types = models.ManyToManyField(
 88        "authentik_stages_authenticator_webauthn.WebAuthnDeviceType", blank=True
 89    )
 90
 91    email_otp_throttling_factor = models.FloatField(default=1)
 92    sms_otp_throttling_factor = models.FloatField(default=1)
 93    totp_otp_throttling_factor = models.FloatField(default=1)
 94    static_otp_throttling_factor = models.FloatField(default=1)
 95
 96    @property
 97    def serializer(self) -> type[BaseSerializer]:
 98        from authentik.stages.authenticator_validate.api import AuthenticatorValidateStageSerializer
 99
100        return AuthenticatorValidateStageSerializer
101
102    @property
103    def view(self) -> type[View]:
104        from authentik.stages.authenticator_validate.stage import AuthenticatorValidateStageView
105
106        return AuthenticatorValidateStageView
107
108    @property
109    def component(self) -> str:
110        return "ak-stage-authenticator-validate-form"
111
112    def get_throttling_factor(self, device_class: DeviceClasses) -> float | None:
113        if device_class == DeviceClasses.EMAIL:
114            return self.email_otp_throttling_factor
115        elif device_class == DeviceClasses.SMS:
116            return self.sms_otp_throttling_factor
117        elif device_class == DeviceClasses.TOTP:
118            return self.totp_otp_throttling_factor
119        elif device_class == DeviceClasses.STATIC:
120            return self.static_otp_throttling_factor
121        return None
122
123    class Meta:
124        verbose_name = _("Authenticator Validation Stage")
125        verbose_name_plural = _("Authenticator Validation Stages")
class DeviceClasses(django.db.models.enums.TextChoices):
15class DeviceClasses(models.TextChoices):
16    """Device classes this stage can validate"""
17
18    # device class must match Device's class name so StaticDevice -> static
19    STATIC = "static", _("Static")
20    TOTP = "totp", _("TOTP")
21    WEBAUTHN = "webauthn", _("WebAuthn")
22    DUO = "duo", _("Duo")
23    SMS = "sms", _("SMS")
24    EMAIL = "email", _("Email")
25
26    @staticmethod
27    def from_model_label(model_label: str) -> DeviceClasses:
28        return getattr(
29            DeviceClasses, model_label.rsplit(".", maxsplit=1)[-1][: -len("device")].upper()
30        )

Device classes this stage can validate

@staticmethod
def from_model_label( model_label: str) -> DeviceClasses:
26    @staticmethod
27    def from_model_label(model_label: str) -> DeviceClasses:
28        return getattr(
29            DeviceClasses, model_label.rsplit(".", maxsplit=1)[-1][: -len("device")].upper()
30        )
def default_device_classes() -> list:
33def default_device_classes() -> list:
34    """By default, accept all device classes"""
35    return [
36        DeviceClasses.STATIC,
37        DeviceClasses.TOTP,
38        DeviceClasses.WEBAUTHN,
39        DeviceClasses.DUO,
40        DeviceClasses.SMS,
41        DeviceClasses.EMAIL,
42    ]

By default, accept all device classes

class AuthenticatorValidateStage(authentik.flows.models.Stage):
 45class AuthenticatorValidateStage(Stage):
 46    """Validate user's configured Multi Factor Authentication."""
 47
 48    not_configured_action = models.TextField(
 49        choices=NotConfiguredAction.choices, default=NotConfiguredAction.SKIP
 50    )
 51
 52    configuration_stages = models.ManyToManyField(
 53        Stage,
 54        blank=True,
 55        default=None,
 56        related_name="+",
 57        help_text=_(
 58            "Stages used to configure Authenticator when user doesn't have any compatible "
 59            "devices. After this configuration Stage passes, the user is not prompted again."
 60        ),
 61    )
 62
 63    device_classes = ArrayField(
 64        models.TextField(choices=DeviceClasses.choices),
 65        help_text=_("Device classes which can be used to authenticate"),
 66        default=default_device_classes,
 67    )
 68
 69    last_auth_threshold = models.TextField(
 70        default="seconds=0",
 71        validators=[timedelta_string_validator],
 72        help_text=_(
 73            "If any of the user's device has been used within this threshold, this "
 74            "stage will be skipped"
 75        ),
 76    )
 77
 78    webauthn_user_verification = models.TextField(
 79        help_text=_("Enforce user verification for WebAuthn devices."),
 80        choices=UserVerification.choices,
 81        default=UserVerification.PREFERRED,
 82    )
 83    webauthn_hints = ArrayField(
 84        models.TextField(choices=WebAuthnHint.choices),
 85        default=list,
 86        blank=True,
 87    )
 88    webauthn_allowed_device_types = models.ManyToManyField(
 89        "authentik_stages_authenticator_webauthn.WebAuthnDeviceType", blank=True
 90    )
 91
 92    email_otp_throttling_factor = models.FloatField(default=1)
 93    sms_otp_throttling_factor = models.FloatField(default=1)
 94    totp_otp_throttling_factor = models.FloatField(default=1)
 95    static_otp_throttling_factor = models.FloatField(default=1)
 96
 97    @property
 98    def serializer(self) -> type[BaseSerializer]:
 99        from authentik.stages.authenticator_validate.api import AuthenticatorValidateStageSerializer
100
101        return AuthenticatorValidateStageSerializer
102
103    @property
104    def view(self) -> type[View]:
105        from authentik.stages.authenticator_validate.stage import AuthenticatorValidateStageView
106
107        return AuthenticatorValidateStageView
108
109    @property
110    def component(self) -> str:
111        return "ak-stage-authenticator-validate-form"
112
113    def get_throttling_factor(self, device_class: DeviceClasses) -> float | None:
114        if device_class == DeviceClasses.EMAIL:
115            return self.email_otp_throttling_factor
116        elif device_class == DeviceClasses.SMS:
117            return self.sms_otp_throttling_factor
118        elif device_class == DeviceClasses.TOTP:
119            return self.totp_otp_throttling_factor
120        elif device_class == DeviceClasses.STATIC:
121            return self.static_otp_throttling_factor
122        return None
123
124    class Meta:
125        verbose_name = _("Authenticator Validation Stage")
126        verbose_name_plural = _("Authenticator Validation Stages")

Validate user's configured Multi Factor Authentication.

def not_configured_action(unknown):

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

configuration_stages

Accessor to the related objects manager on the forward and reverse sides of a many-to-many relation.

In the example::

class Pizza(Model):
    toppings = ManyToManyField(Topping, related_name='pizzas')

Pizza.toppings and Topping.pizzas are ManyToManyDescriptor instances.

Most of the implementation is delegated to a dynamically defined manager class built by create_forward_many_to_many_manager() defined below.

def device_classes(unknown):

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

def last_auth_threshold(unknown):

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

def webauthn_user_verification(unknown):

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

def webauthn_hints(unknown):

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

webauthn_allowed_device_types

Accessor to the related objects manager on the forward and reverse sides of a many-to-many relation.

In the example::

class Pizza(Model):
    toppings = ManyToManyField(Topping, related_name='pizzas')

Pizza.toppings and Topping.pizzas are ManyToManyDescriptor instances.

Most of the implementation is delegated to a dynamically defined manager class built by create_forward_many_to_many_manager() defined below.

def email_otp_throttling_factor(unknown):

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

def sms_otp_throttling_factor(unknown):

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

def totp_otp_throttling_factor(unknown):

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

def static_otp_throttling_factor(unknown):

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

serializer: type[rest_framework.serializers.BaseSerializer]
 97    @property
 98    def serializer(self) -> type[BaseSerializer]:
 99        from authentik.stages.authenticator_validate.api import AuthenticatorValidateStageSerializer
100
101        return AuthenticatorValidateStageSerializer

Get serializer for this model

view: type[django.views.generic.base.View]
103    @property
104    def view(self) -> type[View]:
105        from authentik.stages.authenticator_validate.stage import AuthenticatorValidateStageView
106
107        return AuthenticatorValidateStageView

Return StageView class that implements logic for this stage

component: str
109    @property
110    def component(self) -> str:
111        return "ak-stage-authenticator-validate-form"

Return component used to edit this object

def get_throttling_factor( self, device_class: DeviceClasses) -> float | None:
113    def get_throttling_factor(self, device_class: DeviceClasses) -> float | None:
114        if device_class == DeviceClasses.EMAIL:
115            return self.email_otp_throttling_factor
116        elif device_class == DeviceClasses.SMS:
117            return self.sms_otp_throttling_factor
118        elif device_class == DeviceClasses.TOTP:
119            return self.totp_otp_throttling_factor
120        elif device_class == DeviceClasses.STATIC:
121            return self.static_otp_throttling_factor
122        return None
def get_not_configured_action_display(unknown):

Method descriptor with partial application of the given arguments and keywords.

Supports wrapping existing descriptors and handles non-descriptor callables as instance methods.

def get_webauthn_user_verification_display(unknown):

Method descriptor with partial application of the given arguments and keywords.

Supports wrapping existing descriptors and handles non-descriptor callables as instance methods.

stage_ptr_id
stage_ptr

Accessor to the related object on the forward side of a one-to-one relation.

In the example::

class Restaurant(Model):
    place = OneToOneField(Place, related_name='restaurant')

Restaurant.place is a ForwardOneToOneDescriptor instance.

identificationstage_set

Accessor to the related objects manager on the reverse side of a many-to-one relation.

In the example::

class Child(Model):
    parent = ForeignKey(Parent, related_name='children')

Parent.children is a ReverseManyToOneDescriptor instance.

Most of the implementation is delegated to a dynamically defined manager class built by create_forward_many_to_many_manager() defined below.

class AuthenticatorValidateStage.DoesNotExist(authentik.flows.models.Stage.DoesNotExist):

The requested object does not exist

class AuthenticatorValidateStage.MultipleObjectsReturned(authentik.flows.models.Stage.MultipleObjectsReturned):

The query returned multiple objects when only one was expected.