policies/event_matcher: add model filter (#5802)

* policies/event_matcher: add model filter

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* cleanup

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* improve logic

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* remove t``

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
This commit is contained in:
Jens L 2023-06-12 22:11:11 +02:00 committed by GitHub
parent e5576d486b
commit 05d73f688c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 698 additions and 29 deletions

View File

@ -8,6 +8,7 @@ from rest_framework.viewsets import ViewSet
from authentik.core.api.utils import PassiveSerializer from authentik.core.api.utils import PassiveSerializer
from authentik.lib.utils.reflection import get_apps from authentik.lib.utils.reflection import get_apps
from authentik.policies.event_matcher.models import model_choices
class AppSerializer(PassiveSerializer): class AppSerializer(PassiveSerializer):
@ -29,3 +30,17 @@ class AppsViewSet(ViewSet):
for app in sorted(get_apps(), key=lambda app: app.name): for app in sorted(get_apps(), key=lambda app: app.name):
data.append({"name": app.name, "label": app.verbose_name}) data.append({"name": app.name, "label": app.verbose_name})
return Response(AppSerializer(data, many=True).data) return Response(AppSerializer(data, many=True).data)
class ModelViewSet(ViewSet):
"""Read-only view list all installed models"""
permission_classes = [IsAdminUser]
@extend_schema(responses={200: AppSerializer(many=True)})
def list(self, request: Request) -> Response:
"""Read-only view list all installed models"""
data = []
for name, label in model_choices():
data.append({"name": name, "label": label})
return Response(AppSerializer(data, many=True).data)

View File

@ -94,6 +94,11 @@ class TestAdminAPI(TestCase):
response = self.client.get(reverse("authentik_api:apps-list")) response = self.client.get(reverse("authentik_api:apps-list"))
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
def test_models(self):
"""Test models API"""
response = self.client.get(reverse("authentik_api:models-list"))
self.assertEqual(response.status_code, 200)
@reconcile_app("authentik_outposts") @reconcile_app("authentik_outposts")
def test_system(self): def test_system(self):
"""Test system API""" """Test system API"""

View File

@ -1,7 +1,7 @@
"""API URLs""" """API URLs"""
from django.urls import path from django.urls import path
from authentik.admin.api.meta import AppsViewSet from authentik.admin.api.meta import AppsViewSet, ModelViewSet
from authentik.admin.api.metrics import AdministrationMetricsViewSet from authentik.admin.api.metrics import AdministrationMetricsViewSet
from authentik.admin.api.system import SystemView from authentik.admin.api.system import SystemView
from authentik.admin.api.tasks import TaskViewSet from authentik.admin.api.tasks import TaskViewSet
@ -11,6 +11,7 @@ from authentik.admin.api.workers import WorkerView
api_urlpatterns = [ api_urlpatterns = [
("admin/system_tasks", TaskViewSet, "admin_system_tasks"), ("admin/system_tasks", TaskViewSet, "admin_system_tasks"),
("admin/apps", AppsViewSet, "apps"), ("admin/apps", AppsViewSet, "apps"),
("admin/models", ModelViewSet, "models"),
path( path(
"admin/metrics/", "admin/metrics/",
AdministrationMetricsViewSet.as_view(), AdministrationMetricsViewSet.as_view(),

View File

@ -6,7 +6,7 @@ from rest_framework.viewsets import ModelViewSet
from authentik.core.api.used_by import UsedByMixin from authentik.core.api.used_by import UsedByMixin
from authentik.policies.api.policies import PolicySerializer from authentik.policies.api.policies import PolicySerializer
from authentik.policies.event_matcher.models import EventMatcherPolicy, app_choices from authentik.policies.event_matcher.models import EventMatcherPolicy, app_choices, model_choices
class EventMatcherPolicySerializer(PolicySerializer): class EventMatcherPolicySerializer(PolicySerializer):
@ -21,9 +21,24 @@ class EventMatcherPolicySerializer(PolicySerializer):
"all applications are matched." "all applications are matched."
), ),
) )
model = ChoiceField(
choices=model_choices(),
required=False,
allow_blank=True,
help_text=_(
"Match events created by selected model. "
"When left empty, all models are matched. When an app is selected, "
"all the application's models are matched."
),
)
def validate(self, attrs: dict) -> dict: def validate(self, attrs: dict) -> dict:
if attrs["action"] == "" and attrs["client_ip"] == "" and attrs["app"] == "": if (
attrs["action"] == ""
and attrs["client_ip"] == ""
and attrs["app"] == ""
and attrs["model"] == ""
):
raise ValidationError(_("At least one criteria must be set.")) raise ValidationError(_("At least one criteria must be set."))
return super().validate(attrs) return super().validate(attrs)
@ -33,6 +48,7 @@ class EventMatcherPolicySerializer(PolicySerializer):
"action", "action",
"client_ip", "client_ip",
"app", "app",
"model",
] ]

View File

@ -0,0 +1,21 @@
# Generated by Django 4.1.7 on 2023-05-29 15:24
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("authentik_policies_event_matcher", "0021_alter_eventmatcherpolicy_app"),
]
operations = [
migrations.AddField(
model_name="eventmatcherpolicy",
name="model",
field=models.TextField(
blank=True,
default="",
help_text="Match events created by selected model. When left empty, all models are matched. When an app is selected, all the application's models are matched.",
),
),
]

View File

@ -1,13 +1,19 @@
"""Event Matcher models""" """Event Matcher models"""
from itertools import chain
from django.apps import apps from django.apps import apps
from django.db import models from django.db import models
from django.utils.translation import gettext as _ from django.utils.translation import gettext as _
from rest_framework.serializers import BaseSerializer from rest_framework.serializers import BaseSerializer
from structlog.stdlib import get_logger
from authentik.blueprints.v1.importer import is_model_allowed
from authentik.events.models import Event, EventAction from authentik.events.models import Event, EventAction
from authentik.policies.models import Policy from authentik.policies.models import Policy
from authentik.policies.types import PolicyRequest, PolicyResult from authentik.policies.types import PolicyRequest, PolicyResult
LOGGER = get_logger()
def app_choices() -> list[tuple[str, str]]: def app_choices() -> list[tuple[str, str]]:
"""Get a list of all installed applications that create events. """Get a list of all installed applications that create events.
@ -19,6 +25,18 @@ def app_choices() -> list[tuple[str, str]]:
return choices return choices
def model_choices() -> list[tuple[str, str]]:
"""Get a list of all installed models
Returns a list of tuples containing (dotted.model.path, name)"""
choices = []
for model in apps.get_models():
if not is_model_allowed(model):
continue
name = f"{model._meta.app_label}.{model._meta.model_name}"
choices.append((name, model._meta.verbose_name))
return choices
class EventMatcherPolicy(Policy): class EventMatcherPolicy(Policy):
"""Passes when Event matches selected criteria.""" """Passes when Event matches selected criteria."""
@ -38,6 +56,15 @@ class EventMatcherPolicy(Policy):
"When left empty, all applications are matched." "When left empty, all applications are matched."
), ),
) )
model = models.TextField(
blank=True,
default="",
help_text=_(
"Match events created by selected model. "
"When left empty, all models are matched. When an app is selected, "
"all the application's models are matched."
),
)
client_ip = models.TextField( client_ip = models.TextField(
blank=True, blank=True,
help_text=_( help_text=_(
@ -60,13 +87,55 @@ class EventMatcherPolicy(Policy):
if "event" not in request.context: if "event" not in request.context:
return PolicyResult(False) return PolicyResult(False)
event: Event = request.context["event"] event: Event = request.context["event"]
if event.action == self.action: matches: list[PolicyResult] = []
return PolicyResult(True, "Action matched.") messages = []
if event.client_ip == self.client_ip: checks = [
return PolicyResult(True, "Client IP matched.") self.passes_action,
if event.app == self.app: self.passes_client_ip,
return PolicyResult(True, "App matched.") self.passes_app,
return PolicyResult(False) self.passes_model,
]
for checker in checks:
result = checker(request, event)
if result is None:
continue
LOGGER.info(
"Event matcher check result",
checker=checker.__name__,
result=result,
)
matches.append(result)
passing = any(x.passing for x in matches)
messages = chain(*[x.messages for x in matches])
result = PolicyResult(passing, *messages)
result.source_results = matches
return result
def passes_action(self, request: PolicyRequest, event: Event) -> PolicyResult | None:
"""Check if `self.action` matches"""
if self.action == "":
return None
return PolicyResult(self.action == event.action, "Action matched.")
def passes_client_ip(self, request: PolicyRequest, event: Event) -> PolicyResult | None:
"""Check if `self.client_ip` matches"""
if self.client_ip == "":
return None
return PolicyResult(self.client_ip == event.client_ip, "Client IP matched.")
def passes_app(self, request: PolicyRequest, event: Event) -> PolicyResult | None:
"""Check if `self.app` matches"""
if self.app == "":
return None
return PolicyResult(self.app == event.app, "App matched.")
def passes_model(self, request: PolicyRequest, event: Event) -> PolicyResult | None:
"""Check if `self.model` is set, and pass if it matches the event's model"""
if self.model == "":
return None
event_model_info = event.context.get("model", {})
event_model = f"{event_model_info.get('app')}.{event_model_info.get('model_name')}"
return PolicyResult(event_model == self.model, "Model matched.")
class Meta(Policy.PolicyMeta): class Meta(Policy.PolicyMeta):
verbose_name = _("Event Matcher Policy") verbose_name = _("Event Matcher Policy")

View File

@ -42,6 +42,22 @@ class TestEventMatcherPolicy(TestCase):
self.assertTrue(response.passing) self.assertTrue(response.passing)
self.assertTupleEqual(response.messages, ("App matched.",)) self.assertTupleEqual(response.messages, ("App matched.",))
def test_match_model(self):
"""Test match model"""
event = Event.new(EventAction.LOGIN)
event.context = {
"model": {
"app": "foo",
"model_name": "bar",
}
}
request = PolicyRequest(get_anonymous_user())
request.context["event"] = event
policy: EventMatcherPolicy = EventMatcherPolicy.objects.create(model="foo.bar")
response = policy.passes(request)
self.assertTrue(response.passing)
self.assertTupleEqual(response.messages, ("Model matched.",))
def test_drop(self): def test_drop(self):
"""Test drop event""" """Test drop event"""
event = Event.new(EventAction.LOGIN) event = Event.new(EventAction.LOGIN)
@ -52,6 +68,19 @@ class TestEventMatcherPolicy(TestCase):
response = policy.passes(request) response = policy.passes(request)
self.assertFalse(response.passing) self.assertFalse(response.passing)
def test_drop_multiple(self):
"""Test drop event"""
event = Event.new(EventAction.LOGIN)
event.app = "foo"
event.client_ip = "1.2.3.4"
request = PolicyRequest(get_anonymous_user())
request.context["event"] = event
policy: EventMatcherPolicy = EventMatcherPolicy.objects.create(
client_ip="1.2.3.5", app="bar"
)
response = policy.passes(request)
self.assertFalse(response.passing)
def test_invalid(self): def test_invalid(self):
"""Test passing event""" """Test passing event"""
request = PolicyRequest(get_anonymous_user()) request = PolicyRequest(get_anonymous_user())

View File

@ -3249,6 +3249,84 @@
], ],
"title": "App", "title": "App",
"description": "Match events created by selected application. When left empty, all applications are matched." "description": "Match events created by selected application. When left empty, all applications are matched."
},
"model": {
"type": "string",
"enum": [
"",
"authentik_crypto.certificatekeypair",
"authentik_events.event",
"authentik_events.notificationtransport",
"authentik_events.notification",
"authentik_events.notificationrule",
"authentik_events.notificationwebhookmapping",
"authentik_flows.flow",
"authentik_flows.flowstagebinding",
"authentik_outposts.dockerserviceconnection",
"authentik_outposts.kubernetesserviceconnection",
"authentik_outposts.outpost",
"authentik_policies_dummy.dummypolicy",
"authentik_policies_event_matcher.eventmatcherpolicy",
"authentik_policies_expiry.passwordexpirypolicy",
"authentik_policies_expression.expressionpolicy",
"authentik_policies_password.passwordpolicy",
"authentik_policies_reputation.reputationpolicy",
"authentik_policies_reputation.reputation",
"authentik_policies.policybinding",
"authentik_providers_ldap.ldapprovider",
"authentik_providers_oauth2.scopemapping",
"authentik_providers_oauth2.oauth2provider",
"authentik_providers_oauth2.authorizationcode",
"authentik_providers_oauth2.accesstoken",
"authentik_providers_oauth2.refreshtoken",
"authentik_providers_proxy.proxyprovider",
"authentik_providers_radius.radiusprovider",
"authentik_providers_saml.samlprovider",
"authentik_providers_saml.samlpropertymapping",
"authentik_providers_scim.scimprovider",
"authentik_providers_scim.scimmapping",
"authentik_sources_ldap.ldapsource",
"authentik_sources_ldap.ldappropertymapping",
"authentik_sources_oauth.oauthsource",
"authentik_sources_oauth.useroauthsourceconnection",
"authentik_sources_plex.plexsource",
"authentik_sources_plex.plexsourceconnection",
"authentik_sources_saml.samlsource",
"authentik_sources_saml.usersamlsourceconnection",
"authentik_stages_authenticator_duo.authenticatorduostage",
"authentik_stages_authenticator_duo.duodevice",
"authentik_stages_authenticator_sms.authenticatorsmsstage",
"authentik_stages_authenticator_sms.smsdevice",
"authentik_stages_authenticator_static.authenticatorstaticstage",
"authentik_stages_authenticator_totp.authenticatortotpstage",
"authentik_stages_authenticator_validate.authenticatorvalidatestage",
"authentik_stages_authenticator_webauthn.authenticatewebauthnstage",
"authentik_stages_authenticator_webauthn.webauthndevice",
"authentik_stages_captcha.captchastage",
"authentik_stages_consent.consentstage",
"authentik_stages_consent.userconsent",
"authentik_stages_deny.denystage",
"authentik_stages_dummy.dummystage",
"authentik_stages_email.emailstage",
"authentik_stages_identification.identificationstage",
"authentik_stages_invitation.invitationstage",
"authentik_stages_invitation.invitation",
"authentik_stages_password.passwordstage",
"authentik_stages_prompt.prompt",
"authentik_stages_prompt.promptstage",
"authentik_stages_user_delete.userdeletestage",
"authentik_stages_user_login.userloginstage",
"authentik_stages_user_logout.userlogoutstage",
"authentik_stages_user_write.userwritestage",
"authentik_tenants.tenant",
"authentik_blueprints.blueprintinstance",
"authentik_core.group",
"authentik_core.user",
"authentik_core.application",
"authentik_core.token"
],
"title": "Model",
"description": "Match events created by selected model. When left empty, all models are matched. When an app is selected, all the application's models are matched."
} }
}, },
"required": [] "required": []

View File

@ -65,6 +65,35 @@ paths:
schema: schema:
$ref: '#/components/schemas/GenericError' $ref: '#/components/schemas/GenericError'
description: '' description: ''
/admin/models/:
get:
operationId: admin_models_list
description: Read-only view list all installed models
tags:
- admin
security:
- authentik: []
responses:
'200':
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/App'
description: ''
'400':
content:
application/json:
schema:
$ref: '#/components/schemas/ValidationError'
description: ''
'403':
content:
application/json:
schema:
$ref: '#/components/schemas/GenericError'
description: ''
/admin/system/: /admin/system/:
get: get:
operationId: admin_system_retrieve operationId: admin_system_retrieve
@ -10973,6 +11002,10 @@ paths:
schema: schema:
type: string type: string
format: date-time format: date-time
- in: query
name: model
schema:
type: string
- in: query - in: query
name: name name: name
schema: schema:
@ -29155,6 +29188,82 @@ components:
* `authentik.blueprints` - authentik Blueprints * `authentik.blueprints` - authentik Blueprints
* `authentik.core` - authentik Core * `authentik.core` - authentik Core
* `authentik.enterprise` - authentik Enterprise * `authentik.enterprise` - authentik Enterprise
model:
allOf:
- $ref: '#/components/schemas/ModelEnum'
description: |-
Match events created by selected model. When left empty, all models are matched. When an app is selected, all the application's models are matched.
* `authentik_crypto.certificatekeypair` - Certificate-Key Pair
* `authentik_events.event` - Event
* `authentik_events.notificationtransport` - Notification Transport
* `authentik_events.notification` - Notification
* `authentik_events.notificationrule` - Notification Rule
* `authentik_events.notificationwebhookmapping` - Webhook Mapping
* `authentik_flows.flow` - Flow
* `authentik_flows.flowstagebinding` - Flow Stage Binding
* `authentik_outposts.dockerserviceconnection` - Docker Service-Connection
* `authentik_outposts.kubernetesserviceconnection` - Kubernetes Service-Connection
* `authentik_outposts.outpost` - outpost
* `authentik_policies_dummy.dummypolicy` - Dummy Policy
* `authentik_policies_event_matcher.eventmatcherpolicy` - Event Matcher Policy
* `authentik_policies_expiry.passwordexpirypolicy` - Password Expiry Policy
* `authentik_policies_expression.expressionpolicy` - Expression Policy
* `authentik_policies_password.passwordpolicy` - Password Policy
* `authentik_policies_reputation.reputationpolicy` - Reputation Policy
* `authentik_policies_reputation.reputation` - reputation
* `authentik_policies.policybinding` - Policy Binding
* `authentik_providers_ldap.ldapprovider` - LDAP Provider
* `authentik_providers_oauth2.scopemapping` - Scope Mapping
* `authentik_providers_oauth2.oauth2provider` - OAuth2/OpenID Provider
* `authentik_providers_oauth2.authorizationcode` - Authorization Code
* `authentik_providers_oauth2.accesstoken` - OAuth2 Access Token
* `authentik_providers_oauth2.refreshtoken` - OAuth2 Refresh Token
* `authentik_providers_proxy.proxyprovider` - Proxy Provider
* `authentik_providers_radius.radiusprovider` - Radius Provider
* `authentik_providers_saml.samlprovider` - SAML Provider
* `authentik_providers_saml.samlpropertymapping` - SAML Property Mapping
* `authentik_providers_scim.scimprovider` - SCIM Provider
* `authentik_providers_scim.scimmapping` - SCIM Mapping
* `authentik_sources_ldap.ldapsource` - LDAP Source
* `authentik_sources_ldap.ldappropertymapping` - LDAP Property Mapping
* `authentik_sources_oauth.oauthsource` - OAuth Source
* `authentik_sources_oauth.useroauthsourceconnection` - User OAuth Source Connection
* `authentik_sources_plex.plexsource` - Plex Source
* `authentik_sources_plex.plexsourceconnection` - User Plex Source Connection
* `authentik_sources_saml.samlsource` - SAML Source
* `authentik_sources_saml.usersamlsourceconnection` - User SAML Source Connection
* `authentik_stages_authenticator_duo.authenticatorduostage` - Duo Authenticator Setup Stage
* `authentik_stages_authenticator_duo.duodevice` - Duo Device
* `authentik_stages_authenticator_sms.authenticatorsmsstage` - SMS Authenticator Setup Stage
* `authentik_stages_authenticator_sms.smsdevice` - SMS Device
* `authentik_stages_authenticator_static.authenticatorstaticstage` - Static Authenticator Stage
* `authentik_stages_authenticator_totp.authenticatortotpstage` - TOTP Authenticator Setup Stage
* `authentik_stages_authenticator_validate.authenticatorvalidatestage` - Authenticator Validation Stage
* `authentik_stages_authenticator_webauthn.authenticatewebauthnstage` - WebAuthn Authenticator Setup Stage
* `authentik_stages_authenticator_webauthn.webauthndevice` - WebAuthn Device
* `authentik_stages_captcha.captchastage` - Captcha Stage
* `authentik_stages_consent.consentstage` - Consent Stage
* `authentik_stages_consent.userconsent` - User Consent
* `authentik_stages_deny.denystage` - Deny Stage
* `authentik_stages_dummy.dummystage` - Dummy Stage
* `authentik_stages_email.emailstage` - Email Stage
* `authentik_stages_identification.identificationstage` - Identification Stage
* `authentik_stages_invitation.invitationstage` - Invitation Stage
* `authentik_stages_invitation.invitation` - Invitation
* `authentik_stages_password.passwordstage` - Password Stage
* `authentik_stages_prompt.prompt` - Prompt
* `authentik_stages_prompt.promptstage` - Prompt Stage
* `authentik_stages_user_delete.userdeletestage` - User Delete Stage
* `authentik_stages_user_login.userloginstage` - User Login Stage
* `authentik_stages_user_logout.userlogoutstage` - User Logout Stage
* `authentik_stages_user_write.userwritestage` - User Write Stage
* `authentik_tenants.tenant` - Tenant
* `authentik_blueprints.blueprintinstance` - Blueprint Instance
* `authentik_core.group` - group
* `authentik_core.user` - User
* `authentik_core.application` - Application
* `authentik_core.token` - Token
required: required:
- bound_to - bound_to
- component - component
@ -29265,6 +29374,82 @@ components:
* `authentik.blueprints` - authentik Blueprints * `authentik.blueprints` - authentik Blueprints
* `authentik.core` - authentik Core * `authentik.core` - authentik Core
* `authentik.enterprise` - authentik Enterprise * `authentik.enterprise` - authentik Enterprise
model:
allOf:
- $ref: '#/components/schemas/ModelEnum'
description: |-
Match events created by selected model. When left empty, all models are matched. When an app is selected, all the application's models are matched.
* `authentik_crypto.certificatekeypair` - Certificate-Key Pair
* `authentik_events.event` - Event
* `authentik_events.notificationtransport` - Notification Transport
* `authentik_events.notification` - Notification
* `authentik_events.notificationrule` - Notification Rule
* `authentik_events.notificationwebhookmapping` - Webhook Mapping
* `authentik_flows.flow` - Flow
* `authentik_flows.flowstagebinding` - Flow Stage Binding
* `authentik_outposts.dockerserviceconnection` - Docker Service-Connection
* `authentik_outposts.kubernetesserviceconnection` - Kubernetes Service-Connection
* `authentik_outposts.outpost` - outpost
* `authentik_policies_dummy.dummypolicy` - Dummy Policy
* `authentik_policies_event_matcher.eventmatcherpolicy` - Event Matcher Policy
* `authentik_policies_expiry.passwordexpirypolicy` - Password Expiry Policy
* `authentik_policies_expression.expressionpolicy` - Expression Policy
* `authentik_policies_password.passwordpolicy` - Password Policy
* `authentik_policies_reputation.reputationpolicy` - Reputation Policy
* `authentik_policies_reputation.reputation` - reputation
* `authentik_policies.policybinding` - Policy Binding
* `authentik_providers_ldap.ldapprovider` - LDAP Provider
* `authentik_providers_oauth2.scopemapping` - Scope Mapping
* `authentik_providers_oauth2.oauth2provider` - OAuth2/OpenID Provider
* `authentik_providers_oauth2.authorizationcode` - Authorization Code
* `authentik_providers_oauth2.accesstoken` - OAuth2 Access Token
* `authentik_providers_oauth2.refreshtoken` - OAuth2 Refresh Token
* `authentik_providers_proxy.proxyprovider` - Proxy Provider
* `authentik_providers_radius.radiusprovider` - Radius Provider
* `authentik_providers_saml.samlprovider` - SAML Provider
* `authentik_providers_saml.samlpropertymapping` - SAML Property Mapping
* `authentik_providers_scim.scimprovider` - SCIM Provider
* `authentik_providers_scim.scimmapping` - SCIM Mapping
* `authentik_sources_ldap.ldapsource` - LDAP Source
* `authentik_sources_ldap.ldappropertymapping` - LDAP Property Mapping
* `authentik_sources_oauth.oauthsource` - OAuth Source
* `authentik_sources_oauth.useroauthsourceconnection` - User OAuth Source Connection
* `authentik_sources_plex.plexsource` - Plex Source
* `authentik_sources_plex.plexsourceconnection` - User Plex Source Connection
* `authentik_sources_saml.samlsource` - SAML Source
* `authentik_sources_saml.usersamlsourceconnection` - User SAML Source Connection
* `authentik_stages_authenticator_duo.authenticatorduostage` - Duo Authenticator Setup Stage
* `authentik_stages_authenticator_duo.duodevice` - Duo Device
* `authentik_stages_authenticator_sms.authenticatorsmsstage` - SMS Authenticator Setup Stage
* `authentik_stages_authenticator_sms.smsdevice` - SMS Device
* `authentik_stages_authenticator_static.authenticatorstaticstage` - Static Authenticator Stage
* `authentik_stages_authenticator_totp.authenticatortotpstage` - TOTP Authenticator Setup Stage
* `authentik_stages_authenticator_validate.authenticatorvalidatestage` - Authenticator Validation Stage
* `authentik_stages_authenticator_webauthn.authenticatewebauthnstage` - WebAuthn Authenticator Setup Stage
* `authentik_stages_authenticator_webauthn.webauthndevice` - WebAuthn Device
* `authentik_stages_captcha.captchastage` - Captcha Stage
* `authentik_stages_consent.consentstage` - Consent Stage
* `authentik_stages_consent.userconsent` - User Consent
* `authentik_stages_deny.denystage` - Deny Stage
* `authentik_stages_dummy.dummystage` - Dummy Stage
* `authentik_stages_email.emailstage` - Email Stage
* `authentik_stages_identification.identificationstage` - Identification Stage
* `authentik_stages_invitation.invitationstage` - Invitation Stage
* `authentik_stages_invitation.invitation` - Invitation
* `authentik_stages_password.passwordstage` - Password Stage
* `authentik_stages_prompt.prompt` - Prompt
* `authentik_stages_prompt.promptstage` - Prompt Stage
* `authentik_stages_user_delete.userdeletestage` - User Delete Stage
* `authentik_stages_user_login.userloginstage` - User Login Stage
* `authentik_stages_user_logout.userlogoutstage` - User Logout Stage
* `authentik_stages_user_write.userwritestage` - User Write Stage
* `authentik_tenants.tenant` - Tenant
* `authentik_blueprints.blueprintinstance` - Blueprint Instance
* `authentik_core.group` - group
* `authentik_core.user` - User
* `authentik_core.application` - Application
* `authentik_core.token` - Token
required: required:
- name - name
EventRequest: EventRequest:
@ -31236,6 +31421,150 @@ components:
required: required:
- labels - labels
- name - name
ModelEnum:
enum:
- authentik_crypto.certificatekeypair
- authentik_events.event
- authentik_events.notificationtransport
- authentik_events.notification
- authentik_events.notificationrule
- authentik_events.notificationwebhookmapping
- authentik_flows.flow
- authentik_flows.flowstagebinding
- authentik_outposts.dockerserviceconnection
- authentik_outposts.kubernetesserviceconnection
- authentik_outposts.outpost
- authentik_policies_dummy.dummypolicy
- authentik_policies_event_matcher.eventmatcherpolicy
- authentik_policies_expiry.passwordexpirypolicy
- authentik_policies_expression.expressionpolicy
- authentik_policies_password.passwordpolicy
- authentik_policies_reputation.reputationpolicy
- authentik_policies_reputation.reputation
- authentik_policies.policybinding
- authentik_providers_ldap.ldapprovider
- authentik_providers_oauth2.scopemapping
- authentik_providers_oauth2.oauth2provider
- authentik_providers_oauth2.authorizationcode
- authentik_providers_oauth2.accesstoken
- authentik_providers_oauth2.refreshtoken
- authentik_providers_proxy.proxyprovider
- authentik_providers_radius.radiusprovider
- authentik_providers_saml.samlprovider
- authentik_providers_saml.samlpropertymapping
- authentik_providers_scim.scimprovider
- authentik_providers_scim.scimmapping
- authentik_sources_ldap.ldapsource
- authentik_sources_ldap.ldappropertymapping
- authentik_sources_oauth.oauthsource
- authentik_sources_oauth.useroauthsourceconnection
- authentik_sources_plex.plexsource
- authentik_sources_plex.plexsourceconnection
- authentik_sources_saml.samlsource
- authentik_sources_saml.usersamlsourceconnection
- authentik_stages_authenticator_duo.authenticatorduostage
- authentik_stages_authenticator_duo.duodevice
- authentik_stages_authenticator_sms.authenticatorsmsstage
- authentik_stages_authenticator_sms.smsdevice
- authentik_stages_authenticator_static.authenticatorstaticstage
- authentik_stages_authenticator_totp.authenticatortotpstage
- authentik_stages_authenticator_validate.authenticatorvalidatestage
- authentik_stages_authenticator_webauthn.authenticatewebauthnstage
- authentik_stages_authenticator_webauthn.webauthndevice
- authentik_stages_captcha.captchastage
- authentik_stages_consent.consentstage
- authentik_stages_consent.userconsent
- authentik_stages_deny.denystage
- authentik_stages_dummy.dummystage
- authentik_stages_email.emailstage
- authentik_stages_identification.identificationstage
- authentik_stages_invitation.invitationstage
- authentik_stages_invitation.invitation
- authentik_stages_password.passwordstage
- authentik_stages_prompt.prompt
- authentik_stages_prompt.promptstage
- authentik_stages_user_delete.userdeletestage
- authentik_stages_user_login.userloginstage
- authentik_stages_user_logout.userlogoutstage
- authentik_stages_user_write.userwritestage
- authentik_tenants.tenant
- authentik_blueprints.blueprintinstance
- authentik_core.group
- authentik_core.user
- authentik_core.application
- authentik_core.token
type: string
description: |-
* `authentik_crypto.certificatekeypair` - Certificate-Key Pair
* `authentik_events.event` - Event
* `authentik_events.notificationtransport` - Notification Transport
* `authentik_events.notification` - Notification
* `authentik_events.notificationrule` - Notification Rule
* `authentik_events.notificationwebhookmapping` - Webhook Mapping
* `authentik_flows.flow` - Flow
* `authentik_flows.flowstagebinding` - Flow Stage Binding
* `authentik_outposts.dockerserviceconnection` - Docker Service-Connection
* `authentik_outposts.kubernetesserviceconnection` - Kubernetes Service-Connection
* `authentik_outposts.outpost` - outpost
* `authentik_policies_dummy.dummypolicy` - Dummy Policy
* `authentik_policies_event_matcher.eventmatcherpolicy` - Event Matcher Policy
* `authentik_policies_expiry.passwordexpirypolicy` - Password Expiry Policy
* `authentik_policies_expression.expressionpolicy` - Expression Policy
* `authentik_policies_password.passwordpolicy` - Password Policy
* `authentik_policies_reputation.reputationpolicy` - Reputation Policy
* `authentik_policies_reputation.reputation` - reputation
* `authentik_policies.policybinding` - Policy Binding
* `authentik_providers_ldap.ldapprovider` - LDAP Provider
* `authentik_providers_oauth2.scopemapping` - Scope Mapping
* `authentik_providers_oauth2.oauth2provider` - OAuth2/OpenID Provider
* `authentik_providers_oauth2.authorizationcode` - Authorization Code
* `authentik_providers_oauth2.accesstoken` - OAuth2 Access Token
* `authentik_providers_oauth2.refreshtoken` - OAuth2 Refresh Token
* `authentik_providers_proxy.proxyprovider` - Proxy Provider
* `authentik_providers_radius.radiusprovider` - Radius Provider
* `authentik_providers_saml.samlprovider` - SAML Provider
* `authentik_providers_saml.samlpropertymapping` - SAML Property Mapping
* `authentik_providers_scim.scimprovider` - SCIM Provider
* `authentik_providers_scim.scimmapping` - SCIM Mapping
* `authentik_sources_ldap.ldapsource` - LDAP Source
* `authentik_sources_ldap.ldappropertymapping` - LDAP Property Mapping
* `authentik_sources_oauth.oauthsource` - OAuth Source
* `authentik_sources_oauth.useroauthsourceconnection` - User OAuth Source Connection
* `authentik_sources_plex.plexsource` - Plex Source
* `authentik_sources_plex.plexsourceconnection` - User Plex Source Connection
* `authentik_sources_saml.samlsource` - SAML Source
* `authentik_sources_saml.usersamlsourceconnection` - User SAML Source Connection
* `authentik_stages_authenticator_duo.authenticatorduostage` - Duo Authenticator Setup Stage
* `authentik_stages_authenticator_duo.duodevice` - Duo Device
* `authentik_stages_authenticator_sms.authenticatorsmsstage` - SMS Authenticator Setup Stage
* `authentik_stages_authenticator_sms.smsdevice` - SMS Device
* `authentik_stages_authenticator_static.authenticatorstaticstage` - Static Authenticator Stage
* `authentik_stages_authenticator_totp.authenticatortotpstage` - TOTP Authenticator Setup Stage
* `authentik_stages_authenticator_validate.authenticatorvalidatestage` - Authenticator Validation Stage
* `authentik_stages_authenticator_webauthn.authenticatewebauthnstage` - WebAuthn Authenticator Setup Stage
* `authentik_stages_authenticator_webauthn.webauthndevice` - WebAuthn Device
* `authentik_stages_captcha.captchastage` - Captcha Stage
* `authentik_stages_consent.consentstage` - Consent Stage
* `authentik_stages_consent.userconsent` - User Consent
* `authentik_stages_deny.denystage` - Deny Stage
* `authentik_stages_dummy.dummystage` - Dummy Stage
* `authentik_stages_email.emailstage` - Email Stage
* `authentik_stages_identification.identificationstage` - Identification Stage
* `authentik_stages_invitation.invitationstage` - Invitation Stage
* `authentik_stages_invitation.invitation` - Invitation
* `authentik_stages_password.passwordstage` - Password Stage
* `authentik_stages_prompt.prompt` - Prompt
* `authentik_stages_prompt.promptstage` - Prompt Stage
* `authentik_stages_user_delete.userdeletestage` - User Delete Stage
* `authentik_stages_user_login.userloginstage` - User Login Stage
* `authentik_stages_user_logout.userlogoutstage` - User Logout Stage
* `authentik_stages_user_write.userwritestage` - User Write Stage
* `authentik_tenants.tenant` - Tenant
* `authentik_blueprints.blueprintinstance` - Blueprint Instance
* `authentik_core.group` - group
* `authentik_core.user` - User
* `authentik_core.application` - Application
* `authentik_core.token` - Token
NameIdPolicyEnum: NameIdPolicyEnum:
enum: enum:
- urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress - urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress
@ -35988,6 +36317,82 @@ components:
* `authentik.blueprints` - authentik Blueprints * `authentik.blueprints` - authentik Blueprints
* `authentik.core` - authentik Core * `authentik.core` - authentik Core
* `authentik.enterprise` - authentik Enterprise * `authentik.enterprise` - authentik Enterprise
model:
allOf:
- $ref: '#/components/schemas/ModelEnum'
description: |-
Match events created by selected model. When left empty, all models are matched. When an app is selected, all the application's models are matched.
* `authentik_crypto.certificatekeypair` - Certificate-Key Pair
* `authentik_events.event` - Event
* `authentik_events.notificationtransport` - Notification Transport
* `authentik_events.notification` - Notification
* `authentik_events.notificationrule` - Notification Rule
* `authentik_events.notificationwebhookmapping` - Webhook Mapping
* `authentik_flows.flow` - Flow
* `authentik_flows.flowstagebinding` - Flow Stage Binding
* `authentik_outposts.dockerserviceconnection` - Docker Service-Connection
* `authentik_outposts.kubernetesserviceconnection` - Kubernetes Service-Connection
* `authentik_outposts.outpost` - outpost
* `authentik_policies_dummy.dummypolicy` - Dummy Policy
* `authentik_policies_event_matcher.eventmatcherpolicy` - Event Matcher Policy
* `authentik_policies_expiry.passwordexpirypolicy` - Password Expiry Policy
* `authentik_policies_expression.expressionpolicy` - Expression Policy
* `authentik_policies_password.passwordpolicy` - Password Policy
* `authentik_policies_reputation.reputationpolicy` - Reputation Policy
* `authentik_policies_reputation.reputation` - reputation
* `authentik_policies.policybinding` - Policy Binding
* `authentik_providers_ldap.ldapprovider` - LDAP Provider
* `authentik_providers_oauth2.scopemapping` - Scope Mapping
* `authentik_providers_oauth2.oauth2provider` - OAuth2/OpenID Provider
* `authentik_providers_oauth2.authorizationcode` - Authorization Code
* `authentik_providers_oauth2.accesstoken` - OAuth2 Access Token
* `authentik_providers_oauth2.refreshtoken` - OAuth2 Refresh Token
* `authentik_providers_proxy.proxyprovider` - Proxy Provider
* `authentik_providers_radius.radiusprovider` - Radius Provider
* `authentik_providers_saml.samlprovider` - SAML Provider
* `authentik_providers_saml.samlpropertymapping` - SAML Property Mapping
* `authentik_providers_scim.scimprovider` - SCIM Provider
* `authentik_providers_scim.scimmapping` - SCIM Mapping
* `authentik_sources_ldap.ldapsource` - LDAP Source
* `authentik_sources_ldap.ldappropertymapping` - LDAP Property Mapping
* `authentik_sources_oauth.oauthsource` - OAuth Source
* `authentik_sources_oauth.useroauthsourceconnection` - User OAuth Source Connection
* `authentik_sources_plex.plexsource` - Plex Source
* `authentik_sources_plex.plexsourceconnection` - User Plex Source Connection
* `authentik_sources_saml.samlsource` - SAML Source
* `authentik_sources_saml.usersamlsourceconnection` - User SAML Source Connection
* `authentik_stages_authenticator_duo.authenticatorduostage` - Duo Authenticator Setup Stage
* `authentik_stages_authenticator_duo.duodevice` - Duo Device
* `authentik_stages_authenticator_sms.authenticatorsmsstage` - SMS Authenticator Setup Stage
* `authentik_stages_authenticator_sms.smsdevice` - SMS Device
* `authentik_stages_authenticator_static.authenticatorstaticstage` - Static Authenticator Stage
* `authentik_stages_authenticator_totp.authenticatortotpstage` - TOTP Authenticator Setup Stage
* `authentik_stages_authenticator_validate.authenticatorvalidatestage` - Authenticator Validation Stage
* `authentik_stages_authenticator_webauthn.authenticatewebauthnstage` - WebAuthn Authenticator Setup Stage
* `authentik_stages_authenticator_webauthn.webauthndevice` - WebAuthn Device
* `authentik_stages_captcha.captchastage` - Captcha Stage
* `authentik_stages_consent.consentstage` - Consent Stage
* `authentik_stages_consent.userconsent` - User Consent
* `authentik_stages_deny.denystage` - Deny Stage
* `authentik_stages_dummy.dummystage` - Dummy Stage
* `authentik_stages_email.emailstage` - Email Stage
* `authentik_stages_identification.identificationstage` - Identification Stage
* `authentik_stages_invitation.invitationstage` - Invitation Stage
* `authentik_stages_invitation.invitation` - Invitation
* `authentik_stages_password.passwordstage` - Password Stage
* `authentik_stages_prompt.prompt` - Prompt
* `authentik_stages_prompt.promptstage` - Prompt Stage
* `authentik_stages_user_delete.userdeletestage` - User Delete Stage
* `authentik_stages_user_login.userloginstage` - User Login Stage
* `authentik_stages_user_logout.userlogoutstage` - User Logout Stage
* `authentik_stages_user_write.userwritestage` - User Write Stage
* `authentik_tenants.tenant` - Tenant
* `authentik_blueprints.blueprintinstance` - Blueprint Instance
* `authentik_core.group` - group
* `authentik_core.user` - User
* `authentik_core.application` - Application
* `authentik_core.token` - Token
PatchedEventRequest: PatchedEventRequest:
type: object type: object
description: Event Serializer description: Event Serializer

View File

@ -27,12 +27,6 @@ export class EventMatcherPolicyForm extends ModelForm<EventMatcherPolicy, string
}); });
} }
async load(): Promise<void> {
this.apps = await new AdminApi(DEFAULT_CONFIG).adminAppsList();
}
apps?: App[];
getSuccessMessage(): string { getSuccessMessage(): string {
if (this.instance) { if (this.instance) {
return msg("Successfully updated policy."); return msg("Successfully updated policy.");
@ -133,25 +127,61 @@ export class EventMatcherPolicyForm extends ModelForm<EventMatcherPolicy, string
</p> </p>
</ak-form-element-horizontal> </ak-form-element-horizontal>
<ak-form-element-horizontal label=${msg("App")} name="app"> <ak-form-element-horizontal label=${msg("App")} name="app">
<select class="pf-c-form-control"> <ak-search-select
<option value="" ?selected=${this.instance?.app === undefined}> .fetchObjects=${async (query?: string): Promise<App[]> => {
--------- const items = await new AdminApi(DEFAULT_CONFIG).adminAppsList();
</option> return items.filter((item) =>
${this.apps?.map((app) => { query ? item.name.includes(query) : true,
return html`<option );
value=${app.name} }}
?selected=${this.instance?.app === app.name} .renderElement=${(item: App): string => {
> return item.label;
${app.label} }}
</option>`; .value=${(item: App | undefined): string | undefined => {
})} return item?.name;
</select> }}
.selected=${(item: App): boolean => {
return this.instance?.app === item.name;
}}
?blankable=${true}
>
</ak-search-select>
<p class="pf-c-form__helper-text"> <p class="pf-c-form__helper-text">
${msg( ${msg(
"Match events created by selected application. When left empty, all applications are matched.", "Match events created by selected application. When left empty, all applications are matched.",
)} )}
</p> </p>
</ak-form-element-horizontal> </ak-form-element-horizontal>
<ak-form-element-horizontal label=${msg("Model")} name="model">
<ak-search-select
.fetchObjects=${async (query?: string): Promise<App[]> => {
const items = await new AdminApi(DEFAULT_CONFIG).adminModelsList();
return items
.filter((item) => (query ? item.name.includes(query) : true))
.sort((a, b) => {
if (a.name < b.name) return -1;
if (a.name > b.name) return 1;
return 0;
});
}}
.renderElement=${(item: App): string => {
return `${item.label} (${item.name.split(".")[0]})`;
}}
.value=${(item: App | undefined): string | undefined => {
return item?.name;
}}
.selected=${(item: App): boolean => {
return this.instance?.model === item.name;
}}
?blankable=${true}
>
</ak-search-select>
<p class="pf-c-form__helper-text">
${msg(
"Match events created by selected model. When left empty, all models are matched.",
)}
</p>
</ak-form-element-horizontal>
</div> </div>
</ak-form-group> </ak-form-group>
</form>`; </form>`;