authentik.enterprise.models

Enterprise models

  1"""Enterprise models"""
  2
  3from datetime import timedelta
  4from typing import TYPE_CHECKING
  5from uuid import uuid4
  6
  7from django.contrib.postgres.indexes import HashIndex
  8from django.db import models
  9from django.utils.timezone import now
 10from django.utils.translation import gettext as _
 11from rest_framework.serializers import BaseSerializer
 12
 13from authentik.core.models import ExpiringModel
 14from authentik.lib.models import InternallyManagedMixin, SerializerModel
 15
 16if TYPE_CHECKING:
 17    from authentik.enterprise.license import LicenseKey
 18
 19
 20def usage_expiry():
 21    """Keep license usage records for 3 months"""
 22    return now() + timedelta(days=30 * 3)
 23
 24
 25THRESHOLD_WARNING_ADMIN_WEEKS = 2
 26THRESHOLD_WARNING_USER_WEEKS = 4
 27THRESHOLD_WARNING_EXPIRY_WEEKS = 2
 28THRESHOLD_READ_ONLY_WEEKS = 6
 29
 30
 31class License(SerializerModel):
 32    """An authentik enterprise license"""
 33
 34    license_uuid = models.UUIDField(primary_key=True, editable=False, default=uuid4)
 35    key = models.TextField()
 36
 37    name = models.TextField()
 38    expiry = models.DateTimeField()
 39    internal_users = models.BigIntegerField()
 40    external_users = models.BigIntegerField()
 41
 42    @property
 43    def is_valid(self) -> bool:
 44        return self.expiry >= now()
 45
 46    @property
 47    def serializer(self) -> type[BaseSerializer]:
 48        from authentik.enterprise.api import LicenseSerializer
 49
 50        return LicenseSerializer
 51
 52    @property
 53    def status(self) -> LicenseKey:
 54        """Get parsed license status"""
 55        from authentik.enterprise.license import LicenseKey
 56
 57        return LicenseKey.validate(self.key, check_expiry=False)
 58
 59    class Meta:
 60        indexes = (HashIndex(fields=("key",)),)
 61        verbose_name = _("License")
 62        verbose_name_plural = _("Licenses")
 63
 64
 65class LicenseUsageStatus(models.TextChoices):
 66    """License states an instance/tenant can be in"""
 67
 68    UNLICENSED = "unlicensed"
 69    VALID = "valid"
 70    EXPIRED = "expired"
 71    EXPIRY_SOON = "expiry_soon"
 72    # User limit exceeded, 2 week threshold, show message in admin interface
 73    LIMIT_EXCEEDED_ADMIN = "limit_exceeded_admin"
 74    # User limit exceeded, 4 week threshold, show message in user interface
 75    LIMIT_EXCEEDED_USER = "limit_exceeded_user"
 76    READ_ONLY = "read_only"
 77
 78    @property
 79    def is_valid(self) -> bool:
 80        """Quickly check if a license is valid"""
 81        return self in [LicenseUsageStatus.VALID, LicenseUsageStatus.EXPIRY_SOON]
 82
 83
 84class LicenseUsage(InternallyManagedMixin, ExpiringModel):
 85    """a single license usage record"""
 86
 87    expires = models.DateTimeField(default=usage_expiry)
 88
 89    usage_uuid = models.UUIDField(primary_key=True, editable=False, default=uuid4)
 90
 91    internal_user_count = models.BigIntegerField()
 92    external_user_count = models.BigIntegerField()
 93    status = models.TextField(choices=LicenseUsageStatus.choices)
 94
 95    record_date = models.DateTimeField(auto_now_add=True)
 96
 97    class Meta:
 98        verbose_name = _("License Usage")
 99        verbose_name_plural = _("License Usage Records")
100        indexes = ExpiringModel.Meta.indexes
def usage_expiry():
21def usage_expiry():
22    """Keep license usage records for 3 months"""
23    return now() + timedelta(days=30 * 3)

Keep license usage records for 3 months

THRESHOLD_WARNING_ADMIN_WEEKS = 2
THRESHOLD_WARNING_USER_WEEKS = 4
THRESHOLD_WARNING_EXPIRY_WEEKS = 2
THRESHOLD_READ_ONLY_WEEKS = 6
class License(authentik.lib.models.SerializerModel):
32class License(SerializerModel):
33    """An authentik enterprise license"""
34
35    license_uuid = models.UUIDField(primary_key=True, editable=False, default=uuid4)
36    key = models.TextField()
37
38    name = models.TextField()
39    expiry = models.DateTimeField()
40    internal_users = models.BigIntegerField()
41    external_users = models.BigIntegerField()
42
43    @property
44    def is_valid(self) -> bool:
45        return self.expiry >= now()
46
47    @property
48    def serializer(self) -> type[BaseSerializer]:
49        from authentik.enterprise.api import LicenseSerializer
50
51        return LicenseSerializer
52
53    @property
54    def status(self) -> LicenseKey:
55        """Get parsed license status"""
56        from authentik.enterprise.license import LicenseKey
57
58        return LicenseKey.validate(self.key, check_expiry=False)
59
60    class Meta:
61        indexes = (HashIndex(fields=("key",)),)
62        verbose_name = _("License")
63        verbose_name_plural = _("Licenses")

An authentik enterprise license

def license_uuid(unknown):

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

def key(unknown):

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

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 expiry(unknown):

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

def internal_users(unknown):

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

def external_users(unknown):

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

is_valid: bool
43    @property
44    def is_valid(self) -> bool:
45        return self.expiry >= now()
serializer: type[rest_framework.serializers.BaseSerializer]
47    @property
48    def serializer(self) -> type[BaseSerializer]:
49        from authentik.enterprise.api import LicenseSerializer
50
51        return LicenseSerializer

Get serializer for this model

status
53    @property
54    def status(self) -> LicenseKey:
55        """Get parsed license status"""
56        from authentik.enterprise.license import LicenseKey
57
58        return LicenseKey.validate(self.key, check_expiry=False)

Get parsed license status

def get_next_by_expiry(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_expiry(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 objects(unknown):

The type of the None singleton.

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

The requested object does not exist

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

The query returned multiple objects when only one was expected.

class LicenseUsageStatus(django.db.models.enums.TextChoices):
66class LicenseUsageStatus(models.TextChoices):
67    """License states an instance/tenant can be in"""
68
69    UNLICENSED = "unlicensed"
70    VALID = "valid"
71    EXPIRED = "expired"
72    EXPIRY_SOON = "expiry_soon"
73    # User limit exceeded, 2 week threshold, show message in admin interface
74    LIMIT_EXCEEDED_ADMIN = "limit_exceeded_admin"
75    # User limit exceeded, 4 week threshold, show message in user interface
76    LIMIT_EXCEEDED_USER = "limit_exceeded_user"
77    READ_ONLY = "read_only"
78
79    @property
80    def is_valid(self) -> bool:
81        """Quickly check if a license is valid"""
82        return self in [LicenseUsageStatus.VALID, LicenseUsageStatus.EXPIRY_SOON]

License states an instance/tenant can be in

is_valid: bool
79    @property
80    def is_valid(self) -> bool:
81        """Quickly check if a license is valid"""
82        return self in [LicenseUsageStatus.VALID, LicenseUsageStatus.EXPIRY_SOON]

Quickly check if a license is valid

 85class LicenseUsage(InternallyManagedMixin, ExpiringModel):
 86    """a single license usage record"""
 87
 88    expires = models.DateTimeField(default=usage_expiry)
 89
 90    usage_uuid = models.UUIDField(primary_key=True, editable=False, default=uuid4)
 91
 92    internal_user_count = models.BigIntegerField()
 93    external_user_count = models.BigIntegerField()
 94    status = models.TextField(choices=LicenseUsageStatus.choices)
 95
 96    record_date = models.DateTimeField(auto_now_add=True)
 97
 98    class Meta:
 99        verbose_name = _("License Usage")
100        verbose_name_plural = _("License Usage Records")
101        indexes = ExpiringModel.Meta.indexes

a single license usage record

def expires(unknown):

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

def usage_uuid(unknown):

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

def internal_user_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 external_user_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 status(unknown):

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

def record_date(unknown):

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

def expiring(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_expires(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_expires(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_status_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_next_by_record_date(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_record_date(unknown):

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

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

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

The requested object does not exist

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

The query returned multiple objects when only one was expected.