authentik.stages.authenticator_static.models

Static Authenticator models

  1"""Static Authenticator models"""
  2
  3from base64 import b32encode
  4from os import urandom
  5
  6from django.core.validators import MaxValueValidator
  7from django.db import models
  8from django.utils.translation import gettext_lazy as _
  9from django.views import View
 10from rest_framework.serializers import BaseSerializer
 11
 12from authentik.core.types import UserSettingSerializer
 13from authentik.flows.models import ConfigurableStage, FriendlyNamedStage, Stage
 14from authentik.lib.models import SerializerModel
 15from authentik.stages.authenticator.models import Device, ThrottlingMixin
 16
 17
 18class AuthenticatorStaticStage(ConfigurableStage, FriendlyNamedStage, Stage):
 19    """Setup static token based authentication for the user."""
 20
 21    token_count = models.PositiveIntegerField(default=6)
 22    token_length = models.PositiveIntegerField(default=12, validators=[MaxValueValidator(100)])
 23
 24    @property
 25    def serializer(self) -> type[BaseSerializer]:
 26        from authentik.stages.authenticator_static.api import AuthenticatorStaticStageSerializer
 27
 28        return AuthenticatorStaticStageSerializer
 29
 30    @property
 31    def view(self) -> type[View]:
 32        from authentik.stages.authenticator_static.stage import AuthenticatorStaticStageView
 33
 34        return AuthenticatorStaticStageView
 35
 36    @property
 37    def component(self) -> str:
 38        return "ak-stage-authenticator-static-form"
 39
 40    def ui_user_settings(self) -> UserSettingSerializer | None:
 41        return UserSettingSerializer(
 42            data={
 43                "title": self.friendly_name or str(self._meta.verbose_name),
 44                "component": "ak-user-settings-authenticator-static",
 45            }
 46        )
 47
 48    def __str__(self) -> str:
 49        return f"Static Authenticator Setup Stage {self.name}"
 50
 51    class Meta:
 52        verbose_name = _("Static Authenticator Setup Stage")
 53        verbose_name_plural = _("Static Authenticator Setup Stages")
 54
 55
 56class StaticDevice(SerializerModel, ThrottlingMixin, Device):
 57    """
 58    A static :class:`~authentik.stages.authenticator.models.Device` simply consists of random
 59    tokens shared by the database and the user.
 60
 61    These are frequently used as emergency tokens in case a user's normal
 62    device is lost or unavailable. They can be consumed in any order; each
 63    token will be removed from the database as soon as it is used.
 64
 65    This model has no fields of its own, but serves as a container for
 66    :class:`StaticToken` objects.
 67
 68    .. attribute:: token_set
 69
 70        The RelatedManager for our tokens.
 71
 72    """
 73
 74    @property
 75    def serializer(self) -> type[BaseSerializer]:
 76        from authentik.stages.authenticator_static.api import StaticDeviceSerializer
 77
 78        return StaticDeviceSerializer
 79
 80    def verify_token(self, token):
 81        verify_allowed, _ = self.verify_is_allowed()
 82        if verify_allowed:
 83            match = self.token_set.filter(token=token).first()
 84            if match is not None:
 85                match.delete()
 86                self.throttle_reset()
 87            else:
 88                self.throttle_increment()
 89        else:
 90            match = None
 91
 92        return match is not None
 93
 94    class Meta(Device.Meta):
 95        verbose_name = _("Static Device")
 96        verbose_name_plural = _("Static Devices")
 97
 98
 99class StaticToken(models.Model):
100    """
101    A single token belonging to a :class:`StaticDevice`.
102
103    .. attribute:: device
104
105        *ForeignKey*: A foreign key to :class:`StaticDevice`.
106
107    .. attribute:: token
108
109        *CharField*: A random string up to 100 characters.
110    """
111
112    device = models.ForeignKey(StaticDevice, related_name="token_set", on_delete=models.CASCADE)
113    token = models.CharField(max_length=100, db_index=True)
114
115    class Meta:
116        verbose_name = _("Static Token")
117        verbose_name_plural = _("Static Tokens")
118
119    def __str__(self) -> str:
120        return "Static Token"
121
122    @staticmethod
123    def random_token():
124        """
125        Returns a new random string that can be used as a static token.
126
127        :rtype: bytes
128
129        """
130        return b32encode(urandom(5)).decode("utf-8").lower()
19class AuthenticatorStaticStage(ConfigurableStage, FriendlyNamedStage, Stage):
20    """Setup static token based authentication for the user."""
21
22    token_count = models.PositiveIntegerField(default=6)
23    token_length = models.PositiveIntegerField(default=12, validators=[MaxValueValidator(100)])
24
25    @property
26    def serializer(self) -> type[BaseSerializer]:
27        from authentik.stages.authenticator_static.api import AuthenticatorStaticStageSerializer
28
29        return AuthenticatorStaticStageSerializer
30
31    @property
32    def view(self) -> type[View]:
33        from authentik.stages.authenticator_static.stage import AuthenticatorStaticStageView
34
35        return AuthenticatorStaticStageView
36
37    @property
38    def component(self) -> str:
39        return "ak-stage-authenticator-static-form"
40
41    def ui_user_settings(self) -> UserSettingSerializer | None:
42        return UserSettingSerializer(
43            data={
44                "title": self.friendly_name or str(self._meta.verbose_name),
45                "component": "ak-user-settings-authenticator-static",
46            }
47        )
48
49    def __str__(self) -> str:
50        return f"Static Authenticator Setup Stage {self.name}"
51
52    class Meta:
53        verbose_name = _("Static Authenticator Setup Stage")
54        verbose_name_plural = _("Static Authenticator Setup Stages")

Setup static token based authentication for the user.

def token_count(unknown):

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

def token_length(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]
25    @property
26    def serializer(self) -> type[BaseSerializer]:
27        from authentik.stages.authenticator_static.api import AuthenticatorStaticStageSerializer
28
29        return AuthenticatorStaticStageSerializer

Get serializer for this model

view: type[django.views.generic.base.View]
31    @property
32    def view(self) -> type[View]:
33        from authentik.stages.authenticator_static.stage import AuthenticatorStaticStageView
34
35        return AuthenticatorStaticStageView

Return StageView class that implements logic for this stage

component: str
37    @property
38    def component(self) -> str:
39        return "ak-stage-authenticator-static-form"

Return component used to edit this object

def ui_user_settings(self) -> authentik.core.types.UserSettingSerializer | None:
41    def ui_user_settings(self) -> UserSettingSerializer | None:
42        return UserSettingSerializer(
43            data={
44                "title": self.friendly_name or str(self._meta.verbose_name),
45                "component": "ak-user-settings-authenticator-static",
46            }
47        )

Entrypoint to integrate with User settings. Can either return None if no user settings are available, or a challenge.

configure_flow

Accessor to the related object on the forward side of a many-to-one or one-to-one (via ForwardOneToOneDescriptor subclass) relation.

In the example::

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

Child.parent is a ForwardManyToOneDescriptor instance.

def friendly_name(unknown):

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

configure_flow_id
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.

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

The requested object does not exist

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

The query returned multiple objects when only one was expected.

57class StaticDevice(SerializerModel, ThrottlingMixin, Device):
58    """
59    A static :class:`~authentik.stages.authenticator.models.Device` simply consists of random
60    tokens shared by the database and the user.
61
62    These are frequently used as emergency tokens in case a user's normal
63    device is lost or unavailable. They can be consumed in any order; each
64    token will be removed from the database as soon as it is used.
65
66    This model has no fields of its own, but serves as a container for
67    :class:`StaticToken` objects.
68
69    .. attribute:: token_set
70
71        The RelatedManager for our tokens.
72
73    """
74
75    @property
76    def serializer(self) -> type[BaseSerializer]:
77        from authentik.stages.authenticator_static.api import StaticDeviceSerializer
78
79        return StaticDeviceSerializer
80
81    def verify_token(self, token):
82        verify_allowed, _ = self.verify_is_allowed()
83        if verify_allowed:
84            match = self.token_set.filter(token=token).first()
85            if match is not None:
86                match.delete()
87                self.throttle_reset()
88            else:
89                self.throttle_increment()
90        else:
91            match = None
92
93        return match is not None
94
95    class Meta(Device.Meta):
96        verbose_name = _("Static Device")
97        verbose_name_plural = _("Static Devices")

A static :class:~authentik.stages.authenticator.models.Device simply consists of random tokens shared by the database and the user.

These are frequently used as emergency tokens in case a user's normal device is lost or unavailable. They can be consumed in any order; each token will be removed from the database as soon as it is used.

This model has no fields of its own, but serves as a container for :class:StaticToken objects.

.. attribute:: token_set

The RelatedManager for our tokens.
serializer: type[rest_framework.serializers.BaseSerializer]
75    @property
76    def serializer(self) -> type[BaseSerializer]:
77        from authentik.stages.authenticator_static.api import StaticDeviceSerializer
78
79        return StaticDeviceSerializer

Get serializer for this model

def verify_token(self, token):
81    def verify_token(self, token):
82        verify_allowed, _ = self.verify_is_allowed()
83        if verify_allowed:
84            match = self.token_set.filter(token=token).first()
85            if match is not None:
86                match.delete()
87                self.throttle_reset()
88            else:
89                self.throttle_increment()
90        else:
91            match = None
92
93        return match is not None

Verifies a token. As a rule, the token should no longer be valid if this returns True.

:param str token: The OTP token provided by the user. :rtype: bool

def throttling_failure_timestamp(unknown):

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

def throttling_failure_count(unknown):

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

user

Accessor to the related object on the forward side of a many-to-one or one-to-one (via ForwardOneToOneDescriptor subclass) relation.

In the example::

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

Child.parent is a ForwardManyToOneDescriptor instance.

def name(unknown):

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

def confirmed(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_used(unknown):

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

def created(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_updated(unknown):

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

def get_next_by_created(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_previous_by_created(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_next_by_last_updated(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_previous_by_last_updated(unknown):

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

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

user_id
def id(unknown):

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

token_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 StaticDevice.DoesNotExist(django.core.exceptions.ObjectDoesNotExist):

The requested object does not exist

class StaticDevice.MultipleObjectsReturned(django.core.exceptions.MultipleObjectsReturned):

The query returned multiple objects when only one was expected.

class StaticToken(django.db.models.base.Model):
100class StaticToken(models.Model):
101    """
102    A single token belonging to a :class:`StaticDevice`.
103
104    .. attribute:: device
105
106        *ForeignKey*: A foreign key to :class:`StaticDevice`.
107
108    .. attribute:: token
109
110        *CharField*: A random string up to 100 characters.
111    """
112
113    device = models.ForeignKey(StaticDevice, related_name="token_set", on_delete=models.CASCADE)
114    token = models.CharField(max_length=100, db_index=True)
115
116    class Meta:
117        verbose_name = _("Static Token")
118        verbose_name_plural = _("Static Tokens")
119
120    def __str__(self) -> str:
121        return "Static Token"
122
123    @staticmethod
124    def random_token():
125        """
126        Returns a new random string that can be used as a static token.
127
128        :rtype: bytes
129
130        """
131        return b32encode(urandom(5)).decode("utf-8").lower()

A single token belonging to a :class:StaticDevice.

.. attribute:: device

*ForeignKey*: A foreign key to :class:`StaticDevice`.

.. attribute:: token

*CharField*: A random string up to 100 characters.
device

Accessor to the related object on the forward side of a many-to-one or one-to-one (via ForwardOneToOneDescriptor subclass) relation.

In the example::

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

Child.parent is a ForwardManyToOneDescriptor instance.

def token(unknown):

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

@staticmethod
def random_token():
123    @staticmethod
124    def random_token():
125        """
126        Returns a new random string that can be used as a static token.
127
128        :rtype: bytes
129
130        """
131        return b32encode(urandom(5)).decode("utf-8").lower()

Returns a new random string that can be used as a static token.

:rtype: bytes

device_id
def id(unknown):

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

def objects(unknown):

The type of the None singleton.

class StaticToken.DoesNotExist(django.core.exceptions.ObjectDoesNotExist):

The requested object does not exist

class StaticToken.MultipleObjectsReturned(django.core.exceptions.MultipleObjectsReturned):

The query returned multiple objects when only one was expected.