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
 26def default_device_classes() -> list:
 27    """By default, accept all device classes"""
 28    return [
 29        DeviceClasses.STATIC,
 30        DeviceClasses.TOTP,
 31        DeviceClasses.WEBAUTHN,
 32        DeviceClasses.DUO,
 33        DeviceClasses.SMS,
 34        DeviceClasses.EMAIL,
 35    ]
 36
 37
 38class AuthenticatorValidateStage(Stage):
 39    """Validate user's configured Multi Factor Authentication."""
 40
 41    not_configured_action = models.TextField(
 42        choices=NotConfiguredAction.choices, default=NotConfiguredAction.SKIP
 43    )
 44
 45    configuration_stages = models.ManyToManyField(
 46        Stage,
 47        blank=True,
 48        default=None,
 49        related_name="+",
 50        help_text=_(
 51            "Stages used to configure Authenticator when user doesn't have any compatible "
 52            "devices. After this configuration Stage passes, the user is not prompted again."
 53        ),
 54    )
 55
 56    device_classes = ArrayField(
 57        models.TextField(choices=DeviceClasses.choices),
 58        help_text=_("Device classes which can be used to authenticate"),
 59        default=default_device_classes,
 60    )
 61
 62    last_auth_threshold = models.TextField(
 63        default="seconds=0",
 64        validators=[timedelta_string_validator],
 65        help_text=_(
 66            "If any of the user's device has been used within this threshold, this "
 67            "stage will be skipped"
 68        ),
 69    )
 70
 71    webauthn_user_verification = models.TextField(
 72        help_text=_("Enforce user verification for WebAuthn devices."),
 73        choices=UserVerification.choices,
 74        default=UserVerification.PREFERRED,
 75    )
 76    webauthn_hints = ArrayField(
 77        models.TextField(choices=WebAuthnHint.choices),
 78        default=list,
 79        blank=True,
 80    )
 81    webauthn_allowed_device_types = models.ManyToManyField(
 82        "authentik_stages_authenticator_webauthn.WebAuthnDeviceType", blank=True
 83    )
 84
 85    @property
 86    def serializer(self) -> type[BaseSerializer]:
 87        from authentik.stages.authenticator_validate.api import AuthenticatorValidateStageSerializer
 88
 89        return AuthenticatorValidateStageSerializer
 90
 91    @property
 92    def view(self) -> type[View]:
 93        from authentik.stages.authenticator_validate.stage import AuthenticatorValidateStageView
 94
 95        return AuthenticatorValidateStageView
 96
 97    @property
 98    def component(self) -> str:
 99        return "ak-stage-authenticator-validate-form"
100
101    class Meta:
102        verbose_name = _("Authenticator Validation Stage")
103        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")

Device classes this stage can validate

def default_device_classes() -> list:
27def default_device_classes() -> list:
28    """By default, accept all device classes"""
29    return [
30        DeviceClasses.STATIC,
31        DeviceClasses.TOTP,
32        DeviceClasses.WEBAUTHN,
33        DeviceClasses.DUO,
34        DeviceClasses.SMS,
35        DeviceClasses.EMAIL,
36    ]

By default, accept all device classes

class AuthenticatorValidateStage(authentik.flows.models.Stage):
 39class AuthenticatorValidateStage(Stage):
 40    """Validate user's configured Multi Factor Authentication."""
 41
 42    not_configured_action = models.TextField(
 43        choices=NotConfiguredAction.choices, default=NotConfiguredAction.SKIP
 44    )
 45
 46    configuration_stages = models.ManyToManyField(
 47        Stage,
 48        blank=True,
 49        default=None,
 50        related_name="+",
 51        help_text=_(
 52            "Stages used to configure Authenticator when user doesn't have any compatible "
 53            "devices. After this configuration Stage passes, the user is not prompted again."
 54        ),
 55    )
 56
 57    device_classes = ArrayField(
 58        models.TextField(choices=DeviceClasses.choices),
 59        help_text=_("Device classes which can be used to authenticate"),
 60        default=default_device_classes,
 61    )
 62
 63    last_auth_threshold = models.TextField(
 64        default="seconds=0",
 65        validators=[timedelta_string_validator],
 66        help_text=_(
 67            "If any of the user's device has been used within this threshold, this "
 68            "stage will be skipped"
 69        ),
 70    )
 71
 72    webauthn_user_verification = models.TextField(
 73        help_text=_("Enforce user verification for WebAuthn devices."),
 74        choices=UserVerification.choices,
 75        default=UserVerification.PREFERRED,
 76    )
 77    webauthn_hints = ArrayField(
 78        models.TextField(choices=WebAuthnHint.choices),
 79        default=list,
 80        blank=True,
 81    )
 82    webauthn_allowed_device_types = models.ManyToManyField(
 83        "authentik_stages_authenticator_webauthn.WebAuthnDeviceType", blank=True
 84    )
 85
 86    @property
 87    def serializer(self) -> type[BaseSerializer]:
 88        from authentik.stages.authenticator_validate.api import AuthenticatorValidateStageSerializer
 89
 90        return AuthenticatorValidateStageSerializer
 91
 92    @property
 93    def view(self) -> type[View]:
 94        from authentik.stages.authenticator_validate.stage import AuthenticatorValidateStageView
 95
 96        return AuthenticatorValidateStageView
 97
 98    @property
 99    def component(self) -> str:
100        return "ak-stage-authenticator-validate-form"
101
102    class Meta:
103        verbose_name = _("Authenticator Validation Stage")
104        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.

serializer: type[rest_framework.serializers.BaseSerializer]
86    @property
87    def serializer(self) -> type[BaseSerializer]:
88        from authentik.stages.authenticator_validate.api import AuthenticatorValidateStageSerializer
89
90        return AuthenticatorValidateStageSerializer

Get serializer for this model

view: type[django.views.generic.base.View]
92    @property
93    def view(self) -> type[View]:
94        from authentik.stages.authenticator_validate.stage import AuthenticatorValidateStageView
95
96        return AuthenticatorValidateStageView

Return StageView class that implements logic for this stage

component: str
 98    @property
 99    def component(self) -> str:
100        return "ak-stage-authenticator-validate-form"

Return component used to edit this object

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.