authentik.policies.models
Policy base models
1"""Policy base models""" 2 3from uuid import uuid4 4 5from django.db import models 6from django.utils.translation import gettext_lazy as _ 7from model_utils.managers import InheritanceManager 8from rest_framework.serializers import BaseSerializer 9 10from authentik.lib.models import ( 11 CreatedUpdatedModel, 12 InheritanceAutoManager, 13 InheritanceForeignKey, 14 SerializerModel, 15) 16from authentik.policies.exceptions import PolicyException 17from authentik.policies.types import PolicyRequest, PolicyResult 18 19 20class PolicyEngineMode(models.TextChoices): 21 """Decide how results of multiple policies should be combined.""" 22 23 MODE_ALL = "all", _("all, all policies must pass") # type: "PolicyEngineMode" 24 MODE_ANY = "any", _("any, any policy must pass") # type: "PolicyEngineMode" 25 26 27class PolicyBindingModel(models.Model): 28 """Base Model for objects that have policies applied to them.""" 29 30 pbm_uuid = models.UUIDField(primary_key=True, editable=False, default=uuid4) 31 32 policies = models.ManyToManyField( 33 "Policy", through="PolicyBinding", related_name="bindings", blank=True 34 ) 35 36 policy_engine_mode = models.TextField( 37 choices=PolicyEngineMode.choices, 38 default=PolicyEngineMode.MODE_ANY, 39 ) 40 41 objects = InheritanceManager() 42 43 class Meta: 44 verbose_name = _("Policy Binding Model") 45 verbose_name_plural = _("Policy Binding Models") 46 47 def __str__(self) -> str: 48 return f"PolicyBindingModel {self.pbm_uuid}" 49 50 def supported_policy_binding_targets(self): 51 """Return the list of objects that can be bound to this object.""" 52 return ["policy", "user", "group"] 53 54 55class BoundPolicyQuerySet(models.QuerySet): 56 """QuerySet for filtering enabled bindings for a Policy type""" 57 58 def for_policy(self, policy: Policy): 59 return self.filter(policy__in=policy._default_manager.all()).filter(enabled=True) 60 61 62class PolicyBinding(SerializerModel): 63 """Relationship between a Policy and a PolicyBindingModel.""" 64 65 policy_binding_uuid = models.UUIDField(primary_key=True, editable=False, default=uuid4) 66 67 enabled = models.BooleanField(default=True) 68 69 policy = InheritanceForeignKey( 70 "Policy", 71 on_delete=models.CASCADE, 72 related_name="+", 73 default=None, 74 null=True, 75 blank=True, 76 ) 77 group = models.ForeignKey( 78 # This is quite an ugly hack to prevent pylint from trying 79 # to resolve authentik_core.models.Group 80 # as python import path 81 "authentik_core.Group", 82 on_delete=models.CASCADE, 83 default=None, 84 null=True, 85 blank=True, 86 ) 87 user = models.ForeignKey( 88 "authentik_core.User", 89 on_delete=models.CASCADE, 90 default=None, 91 null=True, 92 blank=True, 93 ) 94 95 target = InheritanceForeignKey( 96 PolicyBindingModel, on_delete=models.CASCADE, related_name="bindings" 97 ) 98 negate = models.BooleanField( 99 default=False, 100 help_text=_("Negates the outcome of the policy. Messages are unaffected."), 101 ) 102 timeout = models.PositiveIntegerField( 103 default=30, help_text=_("Timeout after which Policy execution is terminated.") 104 ) 105 failure_result = models.BooleanField( 106 default=False, help_text=_("Result if the Policy execution fails.") 107 ) 108 109 order = models.IntegerField() 110 111 def passes(self, request: PolicyRequest) -> PolicyResult: 112 """Check if request passes this PolicyBinding, check policy, group or user""" 113 if self.policy: 114 self.policy: Policy 115 return self.policy.passes(request) 116 if self.group: 117 return PolicyResult(self.group.is_member(request.user)) 118 if self.user: 119 return PolicyResult(request.user == self.user) 120 return PolicyResult(False) 121 122 @property 123 def serializer(self) -> type[BaseSerializer]: 124 from authentik.policies.api.bindings import PolicyBindingSerializer 125 126 return PolicyBindingSerializer 127 128 @property 129 def target_type(self) -> str: 130 """Get the target type this binding is applied to""" 131 if self.policy: 132 return "policy" 133 if self.group: 134 return "group" 135 if self.user: 136 return "user" 137 return "invalid" 138 139 @property 140 def target_name(self) -> str: 141 """Get the target name this binding is applied to""" 142 if self.policy: 143 return self.policy.name 144 if self.group: 145 return self.group.name 146 if self.user: 147 return self.user.name 148 return "invalid" 149 150 def __str__(self) -> str: 151 suffix = f"{self.target_type.title()} {self.target_name}" 152 try: 153 return f"Binding from {self.target} #{self.order} to {suffix}" 154 except PolicyBinding.target.RelatedObjectDoesNotExist: 155 return f"Binding - #{self.order} to {suffix}" 156 return "" 157 158 objects = models.Manager() 159 in_use = BoundPolicyQuerySet.as_manager() 160 161 class Meta: 162 verbose_name = _("Policy Binding") 163 verbose_name_plural = _("Policy Bindings") 164 unique_together = ("policy", "target", "order") 165 indexes = [ 166 models.Index(fields=["policy"]), 167 models.Index(fields=["group"]), 168 models.Index(fields=["user"]), 169 models.Index(fields=["target"]), 170 ] 171 172 173class Policy(SerializerModel, CreatedUpdatedModel): 174 """Policies which specify if a user is authorized to use an Application. Can be overridden by 175 other types to add other fields, more logic, etc.""" 176 177 policy_uuid = models.UUIDField(primary_key=True, editable=False, default=uuid4) 178 179 name = models.TextField(unique=True) 180 181 execution_logging = models.BooleanField( 182 default=False, 183 help_text=_( 184 "When this option is enabled, all executions of this policy will be logged. " 185 "By default, only execution errors are logged." 186 ), 187 ) 188 189 objects = InheritanceAutoManager() 190 191 @property 192 def component(self) -> str: 193 """Return component used to edit this object""" 194 raise NotImplementedError 195 196 def __str__(self): 197 return str(self.name) 198 199 def passes(self, request: PolicyRequest) -> PolicyResult: # pragma: no cover 200 """Check if request passes this policy""" 201 raise PolicyException() 202 203 class Meta: 204 base_manager_name = "objects" 205 206 verbose_name = _("Policy") 207 verbose_name_plural = _("Policies") 208 209 permissions = [ 210 ("view_policy_cache", _("View Policy's cache metrics")), 211 ("clear_policy_cache", _("Clear Policy's cache metrics")), 212 ] 213 214 class PolicyMeta: 215 """Base class for the Meta class for all policies""" 216 217 indexes = [ 218 models.Index(fields=["policy_ptr_id"]), 219 ]
21class PolicyEngineMode(models.TextChoices): 22 """Decide how results of multiple policies should be combined.""" 23 24 MODE_ALL = "all", _("all, all policies must pass") # type: "PolicyEngineMode" 25 MODE_ANY = "any", _("any, any policy must pass") # type: "PolicyEngineMode"
Decide how results of multiple policies should be combined.
28class PolicyBindingModel(models.Model): 29 """Base Model for objects that have policies applied to them.""" 30 31 pbm_uuid = models.UUIDField(primary_key=True, editable=False, default=uuid4) 32 33 policies = models.ManyToManyField( 34 "Policy", through="PolicyBinding", related_name="bindings", blank=True 35 ) 36 37 policy_engine_mode = models.TextField( 38 choices=PolicyEngineMode.choices, 39 default=PolicyEngineMode.MODE_ANY, 40 ) 41 42 objects = InheritanceManager() 43 44 class Meta: 45 verbose_name = _("Policy Binding Model") 46 verbose_name_plural = _("Policy Binding Models") 47 48 def __str__(self) -> str: 49 return f"PolicyBindingModel {self.pbm_uuid}" 50 51 def supported_policy_binding_targets(self): 52 """Return the list of objects that can be bound to this object.""" 53 return ["policy", "user", "group"]
Base Model for objects that have policies applied to them.
A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.
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.
A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.
51 def supported_policy_binding_targets(self): 52 """Return the list of objects that can be bound to this object.""" 53 return ["policy", "user", "group"]
Return the list of objects that can be bound to this object.
Method descriptor with partial application of the given arguments and keywords.
Supports wrapping existing descriptors and handles non-descriptor callables as instance methods.
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.
Accessor to the related object on the reverse side of a one-to-one relation.
In the example::
class Restaurant(Model):
place = OneToOneField(Place, related_name='restaurant')
Place.restaurant is a ReverseOneToOneDescriptor instance.
Accessor to the related object on the reverse side of a one-to-one relation.
In the example::
class Restaurant(Model):
place = OneToOneField(Place, related_name='restaurant')
Place.restaurant is a ReverseOneToOneDescriptor instance.
Accessor to the related object on the reverse side of a one-to-one relation.
In the example::
class Restaurant(Model):
place = OneToOneField(Place, related_name='restaurant')
Place.restaurant is a ReverseOneToOneDescriptor instance.
Accessor to the related object on the reverse side of a one-to-one relation.
In the example::
class Restaurant(Model):
place = OneToOneField(Place, related_name='restaurant')
Place.restaurant is a ReverseOneToOneDescriptor instance.
Accessor to the related object on the reverse side of a one-to-one relation.
In the example::
class Restaurant(Model):
place = OneToOneField(Place, related_name='restaurant')
Place.restaurant is a ReverseOneToOneDescriptor instance.
Accessor to the related object on the reverse side of a one-to-one relation.
In the example::
class Restaurant(Model):
place = OneToOneField(Place, related_name='restaurant')
Place.restaurant is a ReverseOneToOneDescriptor instance.
Accessor to the related object on the reverse side of a one-to-one relation.
In the example::
class Restaurant(Model):
place = OneToOneField(Place, related_name='restaurant')
Place.restaurant is a ReverseOneToOneDescriptor instance.
The requested object does not exist
The query returned multiple objects when only one was expected.
56class BoundPolicyQuerySet(models.QuerySet): 57 """QuerySet for filtering enabled bindings for a Policy type""" 58 59 def for_policy(self, policy: Policy): 60 return self.filter(policy__in=policy._default_manager.all()).filter(enabled=True)
QuerySet for filtering enabled bindings for a Policy type
63class PolicyBinding(SerializerModel): 64 """Relationship between a Policy and a PolicyBindingModel.""" 65 66 policy_binding_uuid = models.UUIDField(primary_key=True, editable=False, default=uuid4) 67 68 enabled = models.BooleanField(default=True) 69 70 policy = InheritanceForeignKey( 71 "Policy", 72 on_delete=models.CASCADE, 73 related_name="+", 74 default=None, 75 null=True, 76 blank=True, 77 ) 78 group = models.ForeignKey( 79 # This is quite an ugly hack to prevent pylint from trying 80 # to resolve authentik_core.models.Group 81 # as python import path 82 "authentik_core.Group", 83 on_delete=models.CASCADE, 84 default=None, 85 null=True, 86 blank=True, 87 ) 88 user = models.ForeignKey( 89 "authentik_core.User", 90 on_delete=models.CASCADE, 91 default=None, 92 null=True, 93 blank=True, 94 ) 95 96 target = InheritanceForeignKey( 97 PolicyBindingModel, on_delete=models.CASCADE, related_name="bindings" 98 ) 99 negate = models.BooleanField( 100 default=False, 101 help_text=_("Negates the outcome of the policy. Messages are unaffected."), 102 ) 103 timeout = models.PositiveIntegerField( 104 default=30, help_text=_("Timeout after which Policy execution is terminated.") 105 ) 106 failure_result = models.BooleanField( 107 default=False, help_text=_("Result if the Policy execution fails.") 108 ) 109 110 order = models.IntegerField() 111 112 def passes(self, request: PolicyRequest) -> PolicyResult: 113 """Check if request passes this PolicyBinding, check policy, group or user""" 114 if self.policy: 115 self.policy: Policy 116 return self.policy.passes(request) 117 if self.group: 118 return PolicyResult(self.group.is_member(request.user)) 119 if self.user: 120 return PolicyResult(request.user == self.user) 121 return PolicyResult(False) 122 123 @property 124 def serializer(self) -> type[BaseSerializer]: 125 from authentik.policies.api.bindings import PolicyBindingSerializer 126 127 return PolicyBindingSerializer 128 129 @property 130 def target_type(self) -> str: 131 """Get the target type this binding is applied to""" 132 if self.policy: 133 return "policy" 134 if self.group: 135 return "group" 136 if self.user: 137 return "user" 138 return "invalid" 139 140 @property 141 def target_name(self) -> str: 142 """Get the target name this binding is applied to""" 143 if self.policy: 144 return self.policy.name 145 if self.group: 146 return self.group.name 147 if self.user: 148 return self.user.name 149 return "invalid" 150 151 def __str__(self) -> str: 152 suffix = f"{self.target_type.title()} {self.target_name}" 153 try: 154 return f"Binding from {self.target} #{self.order} to {suffix}" 155 except PolicyBinding.target.RelatedObjectDoesNotExist: 156 return f"Binding - #{self.order} to {suffix}" 157 return "" 158 159 objects = models.Manager() 160 in_use = BoundPolicyQuerySet.as_manager() 161 162 class Meta: 163 verbose_name = _("Policy Binding") 164 verbose_name_plural = _("Policy Bindings") 165 unique_together = ("policy", "target", "order") 166 indexes = [ 167 models.Index(fields=["policy"]), 168 models.Index(fields=["group"]), 169 models.Index(fields=["user"]), 170 models.Index(fields=["target"]), 171 ]
Relationship between a Policy and a PolicyBindingModel.
A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.
A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.
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.
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.
A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.
A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.
A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.
A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.
112 def passes(self, request: PolicyRequest) -> PolicyResult: 113 """Check if request passes this PolicyBinding, check policy, group or user""" 114 if self.policy: 115 self.policy: Policy 116 return self.policy.passes(request) 117 if self.group: 118 return PolicyResult(self.group.is_member(request.user)) 119 if self.user: 120 return PolicyResult(request.user == self.user) 121 return PolicyResult(False)
Check if request passes this PolicyBinding, check policy, group or user
123 @property 124 def serializer(self) -> type[BaseSerializer]: 125 from authentik.policies.api.bindings import PolicyBindingSerializer 126 127 return PolicyBindingSerializer
Get serializer for this model
129 @property 130 def target_type(self) -> str: 131 """Get the target type this binding is applied to""" 132 if self.policy: 133 return "policy" 134 if self.group: 135 return "group" 136 if self.user: 137 return "user" 138 return "invalid"
Get the target type this binding is applied to
140 @property 141 def target_name(self) -> str: 142 """Get the target name this binding is applied to""" 143 if self.policy: 144 return self.policy.name 145 if self.group: 146 return self.group.name 147 if self.user: 148 return self.user.name 149 return "invalid"
Get the target name this binding is applied to
Accessor to the related object on the reverse side of a one-to-one relation.
In the example::
class Restaurant(Model):
place = OneToOneField(Place, related_name='restaurant')
Place.restaurant is a ReverseOneToOneDescriptor instance.
Inherited Members
The requested object does not exist
The query returned multiple objects when only one was expected.
174class Policy(SerializerModel, CreatedUpdatedModel): 175 """Policies which specify if a user is authorized to use an Application. Can be overridden by 176 other types to add other fields, more logic, etc.""" 177 178 policy_uuid = models.UUIDField(primary_key=True, editable=False, default=uuid4) 179 180 name = models.TextField(unique=True) 181 182 execution_logging = models.BooleanField( 183 default=False, 184 help_text=_( 185 "When this option is enabled, all executions of this policy will be logged. " 186 "By default, only execution errors are logged." 187 ), 188 ) 189 190 objects = InheritanceAutoManager() 191 192 @property 193 def component(self) -> str: 194 """Return component used to edit this object""" 195 raise NotImplementedError 196 197 def __str__(self): 198 return str(self.name) 199 200 def passes(self, request: PolicyRequest) -> PolicyResult: # pragma: no cover 201 """Check if request passes this policy""" 202 raise PolicyException() 203 204 class Meta: 205 base_manager_name = "objects" 206 207 verbose_name = _("Policy") 208 verbose_name_plural = _("Policies") 209 210 permissions = [ 211 ("view_policy_cache", _("View Policy's cache metrics")), 212 ("clear_policy_cache", _("Clear Policy's cache metrics")), 213 ] 214 215 class PolicyMeta: 216 """Base class for the Meta class for all policies""" 217 218 indexes = [ 219 models.Index(fields=["policy_ptr_id"]), 220 ]
Policies which specify if a user is authorized to use an Application. Can be overridden by other types to add other fields, more logic, etc.
A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.
A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.
A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.
192 @property 193 def component(self) -> str: 194 """Return component used to edit this object""" 195 raise NotImplementedError
Return component used to edit this object
200 def passes(self, request: PolicyRequest) -> PolicyResult: # pragma: no cover 201 """Check if request passes this policy""" 202 raise PolicyException()
Check if request passes this policy
A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.
A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.
Method descriptor with partial application of the given arguments and keywords.
Supports wrapping existing descriptors and handles non-descriptor callables as instance methods.
Method descriptor with partial application of the given arguments and keywords.
Supports wrapping existing descriptors and handles non-descriptor callables as instance methods.
Method descriptor with partial application of the given arguments and keywords.
Supports wrapping existing descriptors and handles non-descriptor callables as instance methods.
Method descriptor with partial application of the given arguments and keywords.
Supports wrapping existing descriptors and handles non-descriptor callables as instance methods.
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.
Accessor to the related object on the reverse side of a one-to-one relation.
In the example::
class Restaurant(Model):
place = OneToOneField(Place, related_name='restaurant')
Place.restaurant is a ReverseOneToOneDescriptor instance.
Accessor to the related object on the reverse side of a one-to-one relation.
In the example::
class Restaurant(Model):
place = OneToOneField(Place, related_name='restaurant')
Place.restaurant is a ReverseOneToOneDescriptor instance.
Accessor to the related object on the reverse side of a one-to-one relation.
In the example::
class Restaurant(Model):
place = OneToOneField(Place, related_name='restaurant')
Place.restaurant is a ReverseOneToOneDescriptor instance.
Accessor to the related object on the reverse side of a one-to-one relation.
In the example::
class Restaurant(Model):
place = OneToOneField(Place, related_name='restaurant')
Place.restaurant is a ReverseOneToOneDescriptor instance.
Accessor to the related object on the reverse side of a one-to-one relation.
In the example::
class Restaurant(Model):
place = OneToOneField(Place, related_name='restaurant')
Place.restaurant is a ReverseOneToOneDescriptor instance.
Accessor to the related object on the reverse side of a one-to-one relation.
In the example::
class Restaurant(Model):
place = OneToOneField(Place, related_name='restaurant')
Place.restaurant is a ReverseOneToOneDescriptor instance.
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.
Accessor to the related object on the reverse side of a one-to-one relation.
In the example::
class Restaurant(Model):
place = OneToOneField(Place, related_name='restaurant')
Place.restaurant is a ReverseOneToOneDescriptor instance.
Accessor to the related object on the reverse side of a one-to-one relation.
In the example::
class Restaurant(Model):
place = OneToOneField(Place, related_name='restaurant')
Place.restaurant is a ReverseOneToOneDescriptor instance.
Inherited Members
215 class PolicyMeta: 216 """Base class for the Meta class for all policies""" 217 218 indexes = [ 219 models.Index(fields=["policy_ptr_id"]), 220 ]
Base class for the Meta class for all policies
The requested object does not exist
The query returned multiple objects when only one was expected.