Compare commits

...

2 Commits

Author SHA1 Message Date
ad9b5e98ba honor order in api and web
Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space>
2025-04-17 17:22:06 +02:00
e4a21c824a policies: constraint only one type
Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space>
2025-04-17 17:13:39 +02:00
8 changed files with 141 additions and 1 deletions

View File

@ -78,6 +78,7 @@ class PolicyBindingSerializer(ModelSerializer):
"negate",
"enabled",
"order",
"honor_order",
"timeout",
"failure_result",
]
@ -110,7 +111,16 @@ class PolicyBindingFilter(FilterSet):
class Meta:
model = PolicyBinding
fields = ["policy", "policy__isnull", "target", "target_in", "enabled", "order", "timeout"]
fields = [
"policy",
"policy__isnull",
"target",
"target_in",
"enabled",
"order",
"honor_order",
"timeout",
]
class PolicyBindingViewSet(UsedByMixin, ModelViewSet):

View File

@ -0,0 +1,40 @@
# Generated by Django 5.1.8 on 2025-04-17 15:13
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("authentik_core", "0047_delete_oldauthenticatedsession"),
("authentik_policies", "0011_policybinding_failure_result_and_more"),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.AddConstraint(
model_name="policybinding",
constraint=models.CheckConstraint(
condition=models.Q(
models.Q(
("policy_id__isnull", False),
("group_id__isnull", True),
("user_id__isnull", True),
),
models.Q(
("group_id__isnull", False),
("policy_id__isnull", True),
("user_id__isnull", True),
),
models.Q(
("user_id__isnull", False),
("policy_id__isnull", True),
("group_id__isnull", True),
),
_connector="OR",
),
name="authentik_policies_policybinding_only_one_type",
),
),
]

View File

@ -0,0 +1,20 @@
# Generated by Django 5.1.8 on 2025-04-17 15:16
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("authentik_policies", "0012_policybinding_authentik_policies_policybinding_only_one_type"),
]
operations = [
migrations.AddField(
model_name="policybinding",
name="honor_order",
field=models.BooleanField(
default=False, help_text="Honor order when evaluating policies."
),
),
]

View File

@ -3,6 +3,7 @@
from uuid import uuid4
from django.db import models
from django.db.models import Q
from django.utils.translation import gettext_lazy as _
from model_utils.managers import InheritanceManager
from rest_framework.serializers import BaseSerializer
@ -100,6 +101,10 @@ class PolicyBinding(SerializerModel):
)
order = models.IntegerField()
honor_order = models.BooleanField(
default=False,
help_text=_("Honor order when evaluating policies."),
)
def passes(self, request: PolicyRequest) -> PolicyResult:
"""Check if request passes this PolicyBinding, check policy, group or user"""
@ -158,6 +163,28 @@ class PolicyBinding(SerializerModel):
models.Index(fields=["user"]),
models.Index(fields=["target"]),
]
constraints = (
models.CheckConstraint(
condition=(
(
Q(policy_id__isnull=False)
& Q(group_id__isnull=True)
& Q(user_id__isnull=True)
)
| (
Q(group_id__isnull=False)
& Q(policy_id__isnull=True)
& Q(user_id__isnull=True)
)
| (
Q(user_id__isnull=False)
& Q(policy_id__isnull=True)
& Q(group_id__isnull=True)
)
),
name="%(app_label)s_%(class)s_only_one_type",
),
)
class Policy(SerializerModel, CreatedUpdatedModel):

View File

@ -5623,6 +5623,11 @@
"maximum": 2147483647,
"title": "Order"
},
"honor_order": {
"type": "boolean",
"title": "Honor order",
"description": "Honor order when evaluating policies."
},
"timeout": {
"type": "integer",
"minimum": 0,

View File

@ -12092,6 +12092,10 @@ paths:
name: enabled
schema:
type: boolean
- in: query
name: honor_order
schema:
type: boolean
- in: query
name: order
schema:
@ -53311,6 +53315,9 @@ components:
type: integer
maximum: 2147483647
minimum: -2147483648
honor_order:
type: boolean
description: Honor order when evaluating policies.
timeout:
type: integer
maximum: 2147483647
@ -54880,6 +54887,9 @@ components:
type: integer
maximum: 2147483647
minimum: -2147483648
honor_order:
type: boolean
description: Honor order when evaluating policies.
timeout:
type: integer
maximum: 2147483647
@ -54922,6 +54932,9 @@ components:
type: integer
maximum: 2147483647
minimum: -2147483648
honor_order:
type: boolean
description: Honor order when evaluating policies.
timeout:
type: integer
maximum: 2147483647
@ -59183,6 +59196,9 @@ components:
type: integer
maximum: 2147483647
minimum: -2147483648
honor_order:
type: boolean
description: Honor order when evaluating policies.
timeout:
type: integer
maximum: 2147483647

View File

@ -61,6 +61,7 @@ export class BoundPoliciesList extends Table<PolicyBinding> {
new TableColumn(this.allowedTypesLabel),
new TableColumn(msg("Enabled"), "enabled"),
new TableColumn(msg("Timeout"), "timeout"),
new TableColumn(msg("Honor order"), "honor_order"),
new TableColumn(msg("Actions")),
];
}
@ -165,6 +166,7 @@ export class BoundPoliciesList extends Table<PolicyBinding> {
html`${this.getPolicyUserGroupRow(item)}`,
html`<ak-status-label type="warning" ?good=${item.enabled}></ak-status-label>`,
html`${item.timeout}`,
html`<ak-status-label type="info" ?good=${item.honorOrder}></ak-status-label>`,
html` ${this.getObjectEditButton(item)}
<ak-forms-modal size=${PFSize.Medium}>
<span slot="submit"> ${msg("Update")} </span>

View File

@ -310,6 +310,26 @@ export class PolicyBindingForm extends ModelForm<PolicyBinding, string> {
required
/>
</ak-form-element-horizontal>
<ak-form-element-horizontal name="honorOrder">
<label class="pf-c-switch">
<input
class="pf-c-switch__input"
type="checkbox"
?checked=${first(this.instance?.honorOrder, false)}
/>
<span class="pf-c-switch__toggle">
<span class="pf-c-switch__toggle-icon">
<i class="fas fa-check" aria-hidden="true"></i>
</span>
</span>
<span class="pf-c-switch__label">${msg("Honor order")}</span>
</label>
<p class="pf-c-form__helper-text">
${msg(
"Honor the order of policies. Use if policies must be evaluated sequentially following the specified order. May impact performance.",
)}
</p>
</ak-form-element-horizontal>
<ak-form-element-horizontal label=${msg("Timeout")} ?required=${true} name="timeout">
<input
type="number"