From 469899233aae2e95e9b5de6081742275df102ea7 Mon Sep 17 00:00:00 2001 From: Jens L Date: Wed, 21 Jun 2023 15:49:46 +0200 Subject: [PATCH] policies/event_matcher: change empty values to null (#6032) * policies/event_matcher: change empty values to null Signed-off-by: Jens Langhammer * migrate old default values Signed-off-by: Jens Langhammer --------- Signed-off-by: Jens Langhammer --- authentik/policies/event_matcher/api.py | 4 +- ...lter_eventmatcherpolicy_action_and_more.py | 103 ++++++++++++++++++ authentik/policies/event_matcher/models.py | 22 ++-- blueprints/schema.json | 27 +++-- schema.yml | 15 +++ 5 files changed, 152 insertions(+), 19 deletions(-) create mode 100644 authentik/policies/event_matcher/migrations/0023_alter_eventmatcherpolicy_action_and_more.py diff --git a/authentik/policies/event_matcher/api.py b/authentik/policies/event_matcher/api.py index 4d8181915..ea81a8c05 100644 --- a/authentik/policies/event_matcher/api.py +++ b/authentik/policies/event_matcher/api.py @@ -15,7 +15,7 @@ class EventMatcherPolicySerializer(PolicySerializer): app = ChoiceField( choices=app_choices(), required=False, - allow_blank=True, + allow_null=True, help_text=_( "Match events created by selected application. When left empty, " "all applications are matched." @@ -24,7 +24,7 @@ class EventMatcherPolicySerializer(PolicySerializer): model = ChoiceField( choices=model_choices(), required=False, - allow_blank=True, + allow_null=True, help_text=_( "Match events created by selected model. " "When left empty, all models are matched. When an app is selected, " diff --git a/authentik/policies/event_matcher/migrations/0023_alter_eventmatcherpolicy_action_and_more.py b/authentik/policies/event_matcher/migrations/0023_alter_eventmatcherpolicy_action_and_more.py new file mode 100644 index 000000000..9db81658e --- /dev/null +++ b/authentik/policies/event_matcher/migrations/0023_alter_eventmatcherpolicy_action_and_more.py @@ -0,0 +1,103 @@ +# Generated by Django 4.1.7 on 2023-06-21 12:45 + +from django.apps.registry import Apps +from django.db import migrations, models +from django.db.backends.base.schema import BaseDatabaseSchemaEditor + + +def replace_defaults(apps: Apps, schema_editor: BaseDatabaseSchemaEditor): + db_alias = schema_editor.connection.alias + + eventmatcherpolicy = apps.get_model("authentik_policies_event_matcher", "eventmatcherpolicy") + for policy in eventmatcherpolicy.objects.using(db_alias).all(): + changed = False + if policy.action == "": + policy.action = None + changed = True + if policy.app == "": + policy.app = None + changed = True + if policy.client_ip == "": + policy.client_ip = None + changed = True + if policy.model == "": + policy.model = None + changed = True + if not changed: + continue + policy.save() + + +class Migration(migrations.Migration): + dependencies = [ + ("authentik_policies_event_matcher", "0022_eventmatcherpolicy_model"), + ] + + operations = [ + migrations.AlterField( + model_name="eventmatcherpolicy", + name="action", + field=models.TextField( + choices=[ + ("login", "Login"), + ("login_failed", "Login Failed"), + ("logout", "Logout"), + ("user_write", "User Write"), + ("suspicious_request", "Suspicious Request"), + ("password_set", "Password Set"), + ("secret_view", "Secret View"), + ("secret_rotate", "Secret Rotate"), + ("invitation_used", "Invite Used"), + ("authorize_application", "Authorize Application"), + ("source_linked", "Source Linked"), + ("impersonation_started", "Impersonation Started"), + ("impersonation_ended", "Impersonation Ended"), + ("flow_execution", "Flow Execution"), + ("policy_execution", "Policy Execution"), + ("policy_exception", "Policy Exception"), + ("property_mapping_exception", "Property Mapping Exception"), + ("system_task_execution", "System Task Execution"), + ("system_task_exception", "System Task Exception"), + ("system_exception", "System Exception"), + ("configuration_error", "Configuration Error"), + ("model_created", "Model Created"), + ("model_updated", "Model Updated"), + ("model_deleted", "Model Deleted"), + ("email_sent", "Email Sent"), + ("update_available", "Update Available"), + ("custom_", "Custom Prefix"), + ], + default=None, + help_text="Match created events with this action type. When left empty, all action types will be matched.", + null=True, + ), + ), + migrations.AlterField( + model_name="eventmatcherpolicy", + name="app", + field=models.TextField( + default=None, + help_text="Match events created by selected application. When left empty, all applications are matched.", + null=True, + ), + ), + migrations.AlterField( + model_name="eventmatcherpolicy", + name="client_ip", + field=models.TextField( + default=None, + help_text="Matches Event's Client IP (strict matching, for network matching use an Expression Policy)", + null=True, + ), + ), + migrations.AlterField( + model_name="eventmatcherpolicy", + name="model", + field=models.TextField( + default=None, + 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.", + null=True, + ), + ), + migrations.RunPython(replace_defaults), + ] diff --git a/authentik/policies/event_matcher/models.py b/authentik/policies/event_matcher/models.py index 83c44f76c..c4e3ca373 100644 --- a/authentik/policies/event_matcher/models.py +++ b/authentik/policies/event_matcher/models.py @@ -42,23 +42,24 @@ class EventMatcherPolicy(Policy): action = models.TextField( choices=EventAction.choices, - blank=True, + null=True, + default=None, help_text=_( "Match created events with this action type. " "When left empty, all action types will be matched." ), ) app = models.TextField( - blank=True, - default="", + null=True, + default=None, help_text=_( "Match events created by selected application. " "When left empty, all applications are matched." ), ) model = models.TextField( - blank=True, - default="", + null=True, + default=None, help_text=_( "Match events created by selected model. " "When left empty, all models are matched. When an app is selected, " @@ -66,7 +67,8 @@ class EventMatcherPolicy(Policy): ), ) client_ip = models.TextField( - blank=True, + null=True, + default=None, help_text=_( "Matches Event's Client IP (strict matching, " "for network matching use an Expression Policy)" @@ -113,25 +115,25 @@ class EventMatcherPolicy(Policy): def passes_action(self, request: PolicyRequest, event: Event) -> PolicyResult | None: """Check if `self.action` matches""" - if self.action == "": + if self.action is None: 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 == "": + if self.client_ip is None: 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 == "": + if self.app is None: 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 == "": + if self.model is None: return None event_model_info = event.context.get("model", {}) event_model = f"{event_model_info.get('app')}.{event_model_info.get('model_name')}" diff --git a/blueprints/schema.json b/blueprints/schema.json index 69c046195..dd9028b8d 100644 --- a/blueprints/schema.json +++ b/blueprints/schema.json @@ -3155,9 +3155,12 @@ "description": "When this option is enabled, all executions of this policy will be logged. By default, only execution errors are logged." }, "action": { - "type": "string", + "type": [ + "null", + "string" + ], "enum": [ - "", + null, "login", "login_failed", "logout", @@ -3190,14 +3193,21 @@ "description": "Match created events with this action type. When left empty, all action types will be matched." }, "client_ip": { - "type": "string", + "type": [ + "string", + "null" + ], + "minLength": 1, "title": "Client ip", "description": "Matches Event's Client IP (strict matching, for network matching use an Expression Policy)" }, "app": { - "type": "string", + "type": [ + "null", + "string" + ], "enum": [ - "", + null, "authentik.admin", "authentik.api", "authentik.crypto", @@ -3251,9 +3261,12 @@ "description": "Match events created by selected application. When left empty, all applications are matched." }, "model": { - "type": "string", + "type": [ + "null", + "string" + ], "enum": [ - "", + null, "authentik_crypto.certificatekeypair", "authentik_events.event", "authentik_events.notificationtransport", diff --git a/schema.yml b/schema.yml index 211e1e084..4d96e34af 100644 --- a/schema.yml +++ b/schema.yml @@ -10922,6 +10922,7 @@ paths: name: action schema: type: string + nullable: true enum: - authorize_application - configuration_error @@ -29100,6 +29101,7 @@ components: action: allOf: - $ref: '#/components/schemas/EventActions' + nullable: true description: |- Match created events with this action type. When left empty, all action types will be matched. @@ -29132,11 +29134,13 @@ components: * `custom_` - Custom Prefix client_ip: type: string + nullable: true description: Matches Event's Client IP (strict matching, for network matching use an Expression Policy) app: allOf: - $ref: '#/components/schemas/AppEnum' + nullable: true description: |- Match events created by selected application. When left empty, all applications are matched. @@ -29191,6 +29195,7 @@ components: model: allOf: - $ref: '#/components/schemas/ModelEnum' + nullable: true 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. @@ -29286,6 +29291,7 @@ components: action: allOf: - $ref: '#/components/schemas/EventActions' + nullable: true description: |- Match created events with this action type. When left empty, all action types will be matched. @@ -29318,11 +29324,14 @@ components: * `custom_` - Custom Prefix client_ip: type: string + nullable: true + minLength: 1 description: Matches Event's Client IP (strict matching, for network matching use an Expression Policy) app: allOf: - $ref: '#/components/schemas/AppEnum' + nullable: true description: |- Match events created by selected application. When left empty, all applications are matched. @@ -29377,6 +29386,7 @@ components: model: allOf: - $ref: '#/components/schemas/ModelEnum' + nullable: true 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. @@ -36250,6 +36260,7 @@ components: action: allOf: - $ref: '#/components/schemas/EventActions' + nullable: true description: |- Match created events with this action type. When left empty, all action types will be matched. @@ -36282,11 +36293,14 @@ components: * `custom_` - Custom Prefix client_ip: type: string + nullable: true + minLength: 1 description: Matches Event's Client IP (strict matching, for network matching use an Expression Policy) app: allOf: - $ref: '#/components/schemas/AppEnum' + nullable: true description: |- Match events created by selected application. When left empty, all applications are matched. @@ -36341,6 +36355,7 @@ components: model: allOf: - $ref: '#/components/schemas/ModelEnum' + nullable: true 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.