From 53b65a9d1ae52b2097a1ca118051e7dc179cd305 Mon Sep 17 00:00:00 2001 From: Jens L Date: Tue, 24 Jan 2023 12:23:22 +0100 Subject: [PATCH] stages/prompt: field name (#4497) * add prompt field name Signed-off-by: Jens Langhammer * remove numerical prefix Signed-off-by: Jens Langhammer * fix missing name Signed-off-by: Jens Langhammer * use text field Signed-off-by: Jens Langhammer * add description label Signed-off-by: Jens Langhammer * add migrate blueprint to remove old stages Signed-off-by: Jens Langhammer * add task to remove unretrievable blueprints Signed-off-by: Jens Langhammer * lint Signed-off-by: Jens Langhammer * fix blueprint test paths Signed-off-by: Jens Langhammer * fix tests Signed-off-by: Jens Langhammer * actually fix tests Signed-off-by: Jens Langhammer * fix tests even more Signed-off-by: Jens Langhammer * fix fixtures Signed-off-by: Jens Langhammer Signed-off-by: Jens Langhammer --- authentik/blueprints/apps.py | 3 +- authentik/blueprints/settings.py | 5 ++ .../tests/fixtures/static_prompt_export.yaml | 1 + authentik/blueprints/tests/test_packaged.py | 2 +- authentik/blueprints/tests/test_v1.py | 8 ++- authentik/blueprints/v1/labels.py | 1 + authentik/blueprints/v1/tasks.py | 11 +++ .../policies/password/tests/test_flows.py | 2 + authentik/stages/prompt/api.py | 5 +- .../prompt/migrations/0009_prompt_name.py | 40 +++++++++++ authentik/stages/prompt/models.py | 1 + authentik/stages/prompt/tests.py | 8 +++ ...efault-tenant.yaml => default-tenant.yaml} | 0 ...vents-default.yaml => events-default.yaml} | 0 ... => flow-default-authentication-flow.yaml} | 0 ...w-default-authenticator-static-setup.yaml} | 0 ...low-default-authenticator-totp-setup.yaml} | 0 ...default-authenticator-webauthn-setup.yaml} | 0 ...ml => flow-default-invalidation-flow.yaml} | 0 ...vider-authorization-explicit-consent.yaml} | 0 ...vider-authorization-implicit-consent.yaml} | 0 ...> flow-default-source-authentication.yaml} | 0 ...ml => flow-default-source-enrollment.yaml} | 3 +- ...ow-default-source-pre-authentication.yaml} | 0 ...l => flow-default-user-settings-flow.yaml} | 12 ++-- .../{91-flow-oobe.yaml => flow-oobe.yaml} | 22 +++--- ...-change.yaml => flow-password-change.yaml} | 6 +- .../example/flows-enrollment-2-stage.yaml | 29 ++++---- .../flows-enrollment-email-verification.yaml | 25 ++++--- .../flows-recovery-email-verification.yaml | 10 +-- .../migrations/migrate-prompt-name.yaml | 70 +++++++++++++++++++ schema.yml | 14 ++++ tests/e2e/test_flows_authenticators.py | 16 ++--- tests/e2e/test_flows_enroll.py | 42 +++++++---- tests/e2e/test_flows_login.py | 4 +- tests/e2e/test_flows_stage_setup.py | 6 +- tests/e2e/test_provider_ldap.py | 16 ++--- tests/e2e/test_provider_oauth2_github.py | 24 +++---- tests/e2e/test_provider_oauth2_grafana.py | 40 +++++------ tests/e2e/test_provider_oidc.py | 32 ++++----- tests/e2e/test_provider_oidc_implicit.py | 32 ++++----- tests/e2e/test_provider_proxy.py | 24 +++---- tests/e2e/test_provider_saml.py | 48 ++++++------- tests/e2e/test_source_oauth.py | 32 ++++----- tests/e2e/test_source_saml.py | 30 ++++---- web/src/admin/blueprints/BlueprintListPage.ts | 37 +++++++++- web/src/admin/stages/prompt/PromptForm.ts | 11 +++ web/src/admin/stages/prompt/PromptListPage.ts | 9 ++- website/developer-docs/blueprints/index.md | 2 + .../developer-docs/blueprints/v1/structure.md | 4 ++ 50 files changed, 468 insertions(+), 219 deletions(-) create mode 100644 authentik/stages/prompt/migrations/0009_prompt_name.py rename blueprints/default/{90-default-tenant.yaml => default-tenant.yaml} (100%) rename blueprints/default/{40-events-default.yaml => events-default.yaml} (100%) rename blueprints/default/{10-flow-default-authentication-flow.yaml => flow-default-authentication-flow.yaml} (100%) rename blueprints/default/{20-flow-default-authenticator-static-setup.yaml => flow-default-authenticator-static-setup.yaml} (100%) rename blueprints/default/{20-flow-default-authenticator-totp-setup.yaml => flow-default-authenticator-totp-setup.yaml} (100%) rename blueprints/default/{20-flow-default-authenticator-webauthn-setup.yaml => flow-default-authenticator-webauthn-setup.yaml} (100%) rename blueprints/default/{10-flow-default-invalidation-flow.yaml => flow-default-invalidation-flow.yaml} (100%) rename blueprints/default/{20-flow-default-provider-authorization-explicit-consent.yaml => flow-default-provider-authorization-explicit-consent.yaml} (100%) rename blueprints/default/{20-flow-default-provider-authorization-implicit-consent.yaml => flow-default-provider-authorization-implicit-consent.yaml} (100%) rename blueprints/default/{20-flow-default-source-authentication.yaml => flow-default-source-authentication.yaml} (100%) rename blueprints/default/{20-flow-default-source-enrollment.yaml => flow-default-source-enrollment.yaml} (98%) rename blueprints/default/{20-flow-default-source-pre-authentication.yaml => flow-default-source-pre-authentication.yaml} (100%) rename blueprints/default/{30-flow-default-user-settings-flow.yaml => flow-default-user-settings-flow.yaml} (95%) rename blueprints/default/{91-flow-oobe.yaml => flow-oobe.yaml} (95%) rename blueprints/default/{0-flow-password-change.yaml => flow-password-change.yaml} (93%) create mode 100644 blueprints/migrations/migrate-prompt-name.yaml diff --git a/authentik/blueprints/apps.py b/authentik/blueprints/apps.py index 70e9da1a3..681293ed8 100644 --- a/authentik/blueprints/apps.py +++ b/authentik/blueprints/apps.py @@ -57,9 +57,10 @@ class AuthentikBlueprintsConfig(ManagedAppConfig): def reconcile_blueprints_discover(self): """Run blueprint discovery""" - from authentik.blueprints.v1.tasks import blueprints_discover + from authentik.blueprints.v1.tasks import blueprints_discover, clear_failed_blueprints blueprints_discover.delay() + clear_failed_blueprints.delay() def import_models(self): super().import_models() diff --git a/authentik/blueprints/settings.py b/authentik/blueprints/settings.py index ca484d784..3dd627a26 100644 --- a/authentik/blueprints/settings.py +++ b/authentik/blueprints/settings.py @@ -9,4 +9,9 @@ CELERY_BEAT_SCHEDULE = { "schedule": crontab(minute=fqdn_rand("blueprints_v1_discover"), hour="*"), "options": {"queue": "authentik_scheduled"}, }, + "blueprints_v1_cleanup": { + "task": "authentik.blueprints.v1.tasks.clear_failed_blueprints", + "schedule": crontab(minute=fqdn_rand("blueprints_v1_cleanup"), hour="*"), + "options": {"queue": "authentik_scheduled"}, + }, } diff --git a/authentik/blueprints/tests/fixtures/static_prompt_export.yaml b/authentik/blueprints/tests/fixtures/static_prompt_export.yaml index 28d3588cd..fb344806a 100644 --- a/authentik/blueprints/tests/fixtures/static_prompt_export.yaml +++ b/authentik/blueprints/tests/fixtures/static_prompt_export.yaml @@ -4,6 +4,7 @@ entries: pk: cb954fd4-65a5-4ad9-b1ee-180ee9559cf4 model: authentik_stages_prompt.prompt attrs: + name: qwerweqrq field_key: username label: Username type: username diff --git a/authentik/blueprints/tests/test_packaged.py b/authentik/blueprints/tests/test_packaged.py index bbb38bd39..bb618fd75 100644 --- a/authentik/blueprints/tests/test_packaged.py +++ b/authentik/blueprints/tests/test_packaged.py @@ -13,7 +13,7 @@ from authentik.tenants.models import Tenant class TestPackaged(TransactionTestCase): """Empty class, test methods are added dynamically""" - @apply_blueprint("default/90-default-tenant.yaml") + @apply_blueprint("default/default-tenant.yaml") def test_decorator_static(self): """Test @apply_blueprint decorator""" self.assertTrue(Tenant.objects.filter(domain="authentik-default").exists()) diff --git a/authentik/blueprints/tests/test_v1.py b/authentik/blueprints/tests/test_v1.py index e8e68280b..a3d06dbc1 100644 --- a/authentik/blueprints/tests/test_v1.py +++ b/authentik/blueprints/tests/test_v1.py @@ -262,15 +262,21 @@ class TestBlueprintsV1(TransactionTestCase): with transaction_rollback(): # First stage fields username_prompt = Prompt.objects.create( - field_key="username", label="Username", order=0, type=FieldTypes.TEXT + name=generate_id(), + field_key="username", + label="Username", + order=0, + type=FieldTypes.TEXT, ) password = Prompt.objects.create( + name=generate_id(), field_key="password", label="Password", order=1, type=FieldTypes.PASSWORD, ) password_repeat = Prompt.objects.create( + name=generate_id(), field_key="password_repeat", label="Password (repeat)", order=2, diff --git a/authentik/blueprints/v1/labels.py b/authentik/blueprints/v1/labels.py index cdb3039cd..0ac8d40eb 100644 --- a/authentik/blueprints/v1/labels.py +++ b/authentik/blueprints/v1/labels.py @@ -3,3 +3,4 @@ LABEL_AUTHENTIK_SYSTEM = "blueprints.goauthentik.io/system" LABEL_AUTHENTIK_INSTANTIATE = "blueprints.goauthentik.io/instantiate" LABEL_AUTHENTIK_GENERATED = "blueprints.goauthentik.io/generated" +LABEL_AUTHENTIK_DESCRIPTION = "blueprints.goauthentik.io/description" diff --git a/authentik/blueprints/v1/tasks.py b/authentik/blueprints/v1/tasks.py index 442c38455..6f74694e3 100644 --- a/authentik/blueprints/v1/tasks.py +++ b/authentik/blueprints/v1/tasks.py @@ -219,3 +219,14 @@ def apply_blueprint(self: MonitoredTask, instance_pk: str): finally: if instance: instance.save() + + +@CELERY_APP.task() +def clear_failed_blueprints(): + """Remove blueprints which couldn't be fetched""" + # Exclude OCI blueprints as those might be temporarily unavailable + for blueprint in BlueprintInstance.objects.exclude(path__startswith="oci://"): + try: + blueprint.retrieve() + except BlueprintRetrievalFailed: + blueprint.delete() diff --git a/authentik/policies/password/tests/test_flows.py b/authentik/policies/password/tests/test_flows.py index 7c212c091..42e1ae558 100644 --- a/authentik/policies/password/tests/test_flows.py +++ b/authentik/policies/password/tests/test_flows.py @@ -4,6 +4,7 @@ from django.urls.base import reverse from authentik.core.tests.utils import create_test_admin_user, create_test_flow from authentik.flows.models import FlowDesignation, FlowStageBinding from authentik.flows.tests import FlowTestCase +from authentik.lib.generators import generate_id from authentik.policies.password.models import PasswordPolicy from authentik.stages.prompt.models import FieldTypes, Prompt, PromptStage @@ -16,6 +17,7 @@ class TestPasswordPolicyFlow(FlowTestCase): self.flow = create_test_flow(FlowDesignation.AUTHENTICATION) password_prompt = Prompt.objects.create( + name=generate_id(), field_key="password", label="PASSWORD_LABEL", type=FieldTypes.PASSWORD, diff --git a/authentik/stages/prompt/api.py b/authentik/stages/prompt/api.py index 6af7d2609..a95909252 100644 --- a/authentik/stages/prompt/api.py +++ b/authentik/stages/prompt/api.py @@ -42,6 +42,7 @@ class PromptSerializer(ModelSerializer): model = Prompt fields = [ "pk", + "name", "field_key", "label", "type", @@ -59,5 +60,5 @@ class PromptViewSet(UsedByMixin, ModelViewSet): queryset = Prompt.objects.all().prefetch_related("promptstage_set") serializer_class = PromptSerializer - filterset_fields = ["field_key", "label", "type", "placeholder"] - search_fields = ["field_key", "label", "type", "placeholder"] + filterset_fields = ["field_key", "name", "label", "type", "placeholder"] + search_fields = ["field_key", "name", "label", "type", "placeholder"] diff --git a/authentik/stages/prompt/migrations/0009_prompt_name.py b/authentik/stages/prompt/migrations/0009_prompt_name.py new file mode 100644 index 000000000..6a010ed8e --- /dev/null +++ b/authentik/stages/prompt/migrations/0009_prompt_name.py @@ -0,0 +1,40 @@ +# Generated by Django 4.1.5 on 2023-01-23 19:42 + +from django.apps.registry import Apps +from django.db import migrations, models +from django.db.backends.base.schema import BaseDatabaseSchemaEditor + + +def set_generated_name(apps: Apps, schema_editor: BaseDatabaseSchemaEditor): + db_alias = schema_editor.connection.alias + Prompt = apps.get_model("authentik_stages_prompt", "prompt") + + for prompt in Prompt.objects.using(db_alias).all(): + name = prompt.field_key + stage = prompt.promptstage_set.order_by("name").first() + if stage: + name += "_" + stage.name + prompt.name = name + prompt.save() + + +class Migration(migrations.Migration): + + dependencies = [ + ("authentik_stages_prompt", "0008_alter_prompt_type"), + ] + + operations = [ + migrations.AddField( + model_name="prompt", + name="name", + field=models.TextField(default="", unique=False, db_index=False, blank=False), + preserve_default=False, + ), + migrations.RunPython(code=set_generated_name), + migrations.AlterField( + model_name="prompt", + name="name", + field=models.TextField(unique=True, blank=False, db_index=True), + ), + ] diff --git a/authentik/stages/prompt/models.py b/authentik/stages/prompt/models.py index 69ff29ff8..87bbf4437 100644 --- a/authentik/stages/prompt/models.py +++ b/authentik/stages/prompt/models.py @@ -96,6 +96,7 @@ class Prompt(SerializerModel): """Single Prompt, part of a prompt stage.""" prompt_uuid = models.UUIDField(primary_key=True, editable=False, default=uuid4) + name = models.TextField(unique=True, blank=False) field_key = models.TextField( help_text=_("Name of the form field, also used to store the value") diff --git a/authentik/stages/prompt/tests.py b/authentik/stages/prompt/tests.py index cda5ab8dc..4f593d1b5 100644 --- a/authentik/stages/prompt/tests.py +++ b/authentik/stages/prompt/tests.py @@ -30,6 +30,7 @@ class TestPromptStage(FlowTestCase): self.factory = RequestFactory() self.flow = create_test_flow() username_prompt = Prompt.objects.create( + name=generate_id(), field_key="username_prompt", label="USERNAME_LABEL", type=FieldTypes.USERNAME, @@ -37,6 +38,7 @@ class TestPromptStage(FlowTestCase): placeholder="USERNAME_PLACEHOLDER", ) text_prompt = Prompt.objects.create( + name=generate_id(), field_key="text_prompt", label="TEXT_LABEL", type=FieldTypes.TEXT, @@ -44,6 +46,7 @@ class TestPromptStage(FlowTestCase): placeholder="TEXT_PLACEHOLDER", ) email_prompt = Prompt.objects.create( + name=generate_id(), field_key="email_prompt", label="EMAIL_LABEL", type=FieldTypes.EMAIL, @@ -51,6 +54,7 @@ class TestPromptStage(FlowTestCase): placeholder="EMAIL_PLACEHOLDER", ) password_prompt = Prompt.objects.create( + name=generate_id(), field_key="password_prompt", label="PASSWORD_LABEL", type=FieldTypes.PASSWORD, @@ -58,6 +62,7 @@ class TestPromptStage(FlowTestCase): placeholder="PASSWORD_PLACEHOLDER", ) password2_prompt = Prompt.objects.create( + name=generate_id(), field_key="password2_prompt", label="PASSWORD_LABEL", type=FieldTypes.PASSWORD, @@ -65,6 +70,7 @@ class TestPromptStage(FlowTestCase): placeholder="PASSWORD_PLACEHOLDER", ) number_prompt = Prompt.objects.create( + name=generate_id(), field_key="number_prompt", label="NUMBER_LABEL", type=FieldTypes.NUMBER, @@ -72,12 +78,14 @@ class TestPromptStage(FlowTestCase): placeholder="NUMBER_PLACEHOLDER", ) hidden_prompt = Prompt.objects.create( + name=generate_id(), field_key="hidden_prompt", type=FieldTypes.HIDDEN, required=True, placeholder="HIDDEN_PLACEHOLDER", ) static_prompt = Prompt.objects.create( + name=generate_id(), field_key="static_prompt", type=FieldTypes.STATIC, required=True, diff --git a/blueprints/default/90-default-tenant.yaml b/blueprints/default/default-tenant.yaml similarity index 100% rename from blueprints/default/90-default-tenant.yaml rename to blueprints/default/default-tenant.yaml diff --git a/blueprints/default/40-events-default.yaml b/blueprints/default/events-default.yaml similarity index 100% rename from blueprints/default/40-events-default.yaml rename to blueprints/default/events-default.yaml diff --git a/blueprints/default/10-flow-default-authentication-flow.yaml b/blueprints/default/flow-default-authentication-flow.yaml similarity index 100% rename from blueprints/default/10-flow-default-authentication-flow.yaml rename to blueprints/default/flow-default-authentication-flow.yaml diff --git a/blueprints/default/20-flow-default-authenticator-static-setup.yaml b/blueprints/default/flow-default-authenticator-static-setup.yaml similarity index 100% rename from blueprints/default/20-flow-default-authenticator-static-setup.yaml rename to blueprints/default/flow-default-authenticator-static-setup.yaml diff --git a/blueprints/default/20-flow-default-authenticator-totp-setup.yaml b/blueprints/default/flow-default-authenticator-totp-setup.yaml similarity index 100% rename from blueprints/default/20-flow-default-authenticator-totp-setup.yaml rename to blueprints/default/flow-default-authenticator-totp-setup.yaml diff --git a/blueprints/default/20-flow-default-authenticator-webauthn-setup.yaml b/blueprints/default/flow-default-authenticator-webauthn-setup.yaml similarity index 100% rename from blueprints/default/20-flow-default-authenticator-webauthn-setup.yaml rename to blueprints/default/flow-default-authenticator-webauthn-setup.yaml diff --git a/blueprints/default/10-flow-default-invalidation-flow.yaml b/blueprints/default/flow-default-invalidation-flow.yaml similarity index 100% rename from blueprints/default/10-flow-default-invalidation-flow.yaml rename to blueprints/default/flow-default-invalidation-flow.yaml diff --git a/blueprints/default/20-flow-default-provider-authorization-explicit-consent.yaml b/blueprints/default/flow-default-provider-authorization-explicit-consent.yaml similarity index 100% rename from blueprints/default/20-flow-default-provider-authorization-explicit-consent.yaml rename to blueprints/default/flow-default-provider-authorization-explicit-consent.yaml diff --git a/blueprints/default/20-flow-default-provider-authorization-implicit-consent.yaml b/blueprints/default/flow-default-provider-authorization-implicit-consent.yaml similarity index 100% rename from blueprints/default/20-flow-default-provider-authorization-implicit-consent.yaml rename to blueprints/default/flow-default-provider-authorization-implicit-consent.yaml diff --git a/blueprints/default/20-flow-default-source-authentication.yaml b/blueprints/default/flow-default-source-authentication.yaml similarity index 100% rename from blueprints/default/20-flow-default-source-authentication.yaml rename to blueprints/default/flow-default-source-authentication.yaml diff --git a/blueprints/default/20-flow-default-source-enrollment.yaml b/blueprints/default/flow-default-source-enrollment.yaml similarity index 98% rename from blueprints/default/20-flow-default-source-enrollment.yaml rename to blueprints/default/flow-default-source-enrollment.yaml index e9d595298..9618f16ad 100644 --- a/blueprints/default/20-flow-default-source-enrollment.yaml +++ b/blueprints/default/flow-default-source-enrollment.yaml @@ -17,9 +17,10 @@ entries: placeholder_expression: false required: true type: text - identifiers: field_key: username label: Username + identifiers: + name: default-source-enrollment-field-username id: prompt-field-username model: authentik_stages_prompt.prompt - attrs: diff --git a/blueprints/default/20-flow-default-source-pre-authentication.yaml b/blueprints/default/flow-default-source-pre-authentication.yaml similarity index 100% rename from blueprints/default/20-flow-default-source-pre-authentication.yaml rename to blueprints/default/flow-default-source-pre-authentication.yaml diff --git a/blueprints/default/30-flow-default-user-settings-flow.yaml b/blueprints/default/flow-default-user-settings-flow.yaml similarity index 95% rename from blueprints/default/30-flow-default-user-settings-flow.yaml rename to blueprints/default/flow-default-user-settings-flow.yaml index 0dee0d245..aba142a1d 100644 --- a/blueprints/default/30-flow-default-user-settings-flow.yaml +++ b/blueprints/default/flow-default-user-settings-flow.yaml @@ -21,9 +21,10 @@ entries: placeholder_expression: true required: true type: text - identifiers: field_key: username label: Username + identifiers: + name: default-user-settings-field-username id: prompt-field-username model: authentik_stages_prompt.prompt - attrs: @@ -36,9 +37,10 @@ entries: placeholder_expression: true required: true type: text - identifiers: field_key: name label: Name + identifiers: + name: default-user-settings-field-name id: prompt-field-name model: authentik_stages_prompt.prompt - attrs: @@ -51,9 +53,10 @@ entries: placeholder_expression: true required: true type: email - identifiers: field_key: email label: Email + identifiers: + name: default-user-settings-field-email id: prompt-field-email model: authentik_stages_prompt.prompt - attrs: @@ -66,9 +69,10 @@ entries: placeholder_expression: true required: true type: ak-locale - identifiers: field_key: attributes.settings.locale label: Locale + identifiers: + name: default-user-settings-field-locale id: prompt-field-locale model: authentik_stages_prompt.prompt - attrs: diff --git a/blueprints/default/91-flow-oobe.yaml b/blueprints/default/flow-oobe.yaml similarity index 95% rename from blueprints/default/91-flow-oobe.yaml rename to blueprints/default/flow-oobe.yaml index 296778e05..d72f8d652 100644 --- a/blueprints/default/91-flow-oobe.yaml +++ b/blueprints/default/flow-oobe.yaml @@ -19,10 +19,11 @@ entries: required: true sub_text: '' type: static - id: prompt-field-header - identifiers: field_key: oobe-header-text label: oobe-header-text + id: prompt-field-header + identifiers: + name: initial-setup-field-header model: authentik_stages_prompt.prompt - attrs: order: 101 @@ -31,10 +32,11 @@ entries: required: true sub_text: '' type: email + field_key: email + label: Email id: prompt-field-email identifiers: - field_key: admin_email - label: Email + name: initial-setup-field-email model: authentik_stages_prompt.prompt - attrs: order: 300 @@ -43,10 +45,11 @@ entries: required: true sub_text: '' type: password - id: prompt-field-password - identifiers: field_key: password label: Password + id: prompt-field-password + identifiers: + name: initial-setup-field-password model: authentik_stages_prompt.prompt - attrs: order: 301 @@ -55,10 +58,11 @@ entries: required: true sub_text: '' type: password - id: prompt-field-password-repeat - identifiers: field_key: password_repeat label: Password (repeat) + id: prompt-field-password-repeat + identifiers: + name: initial-setup-field-password-repeat model: authentik_stages_prompt.prompt - attrs: expression: | @@ -66,8 +70,6 @@ entries: # by injecting "pending_user" akadmin = ak_user_by(username="akadmin") context["flow_plan"].context["pending_user"] = akadmin - # Remap the email value - context["prompt_data"]["email"] = context["prompt_data"]["admin_email"] return True id: policy-default-oobe-prefill-user identifiers: diff --git a/blueprints/default/0-flow-password-change.yaml b/blueprints/default/flow-password-change.yaml similarity index 93% rename from blueprints/default/0-flow-password-change.yaml rename to blueprints/default/flow-password-change.yaml index d385d498d..2c0f8db21 100644 --- a/blueprints/default/0-flow-password-change.yaml +++ b/blueprints/default/flow-password-change.yaml @@ -17,9 +17,10 @@ entries: placeholder_expression: false required: true type: password - identifiers: field_key: password label: Password + identifiers: + name: default-password-change-field-password id: prompt-field-password model: authentik_stages_prompt.prompt - attrs: @@ -28,9 +29,10 @@ entries: placeholder_expression: false required: true type: password - identifiers: field_key: password_repeat label: Password (repeat) + identifiers: + name: default-password-change-field-password-repeat id: prompt-field-password-repeat model: authentik_stages_prompt.prompt - attrs: diff --git a/blueprints/example/flows-enrollment-2-stage.yaml b/blueprints/example/flows-enrollment-2-stage.yaml index 592dd8033..6365eed00 100644 --- a/blueprints/example/flows-enrollment-2-stage.yaml +++ b/blueprints/example/flows-enrollment-2-stage.yaml @@ -13,56 +13,61 @@ entries: title: Welcome to authentik! designation: enrollment authentication: require_unauthenticated - - identifiers: + - id: prompt-field-username + model: authentik_stages_prompt.prompt + identifiers: + name: default-enrollment-field-username + attrs: field_key: username label: Username - id: prompt-field-username - model: authentik_stages_prompt.prompt - attrs: type: username required: true placeholder: Username placeholder_expression: false order: 0 - identifiers: - field_key: password - label: Password + name: default-enrollment-field-password id: prompt-field-password model: authentik_stages_prompt.prompt attrs: + field_key: password + label: Password type: password required: true placeholder: Password placeholder_expression: false order: 0 - identifiers: - field_key: password_repeat - label: Password (repeat) + name: default-enrollment-field-password-repeat id: prompt-field-password-repeat model: authentik_stages_prompt.prompt attrs: + field_key: password_repeat + label: Password (repeat) type: password required: true placeholder: Password (repeat) placeholder_expression: false order: 1 - identifiers: - field_key: name - label: Name + name: default-enrollment-field-name id: prompt-field-name model: authentik_stages_prompt.prompt attrs: + field_key: name + label: Name type: text required: true placeholder: Name placeholder_expression: false order: 0 - identifiers: - field_key: email - label: Email + name: default-enrollment-field-email id: prompt-field-email model: authentik_stages_prompt.prompt attrs: + field_key: email + label: Email type: email required: true placeholder: Email diff --git a/blueprints/example/flows-enrollment-email-verification.yaml b/blueprints/example/flows-enrollment-email-verification.yaml index 20136c73c..09f1563b0 100644 --- a/blueprints/example/flows-enrollment-email-verification.yaml +++ b/blueprints/example/flows-enrollment-email-verification.yaml @@ -14,55 +14,60 @@ entries: designation: enrollment authentication: require_unauthenticated - identifiers: - field_key: username - label: Username + name: default-enrollment-field-username id: prompt-field-username model: authentik_stages_prompt.prompt attrs: + field_key: username + label: Username type: username required: true placeholder: Username placeholder_expression: false order: 0 - identifiers: - field_key: password - label: Password + name: default-enrollment-field-password id: prompt-field-password model: authentik_stages_prompt.prompt attrs: + field_key: password + label: Password type: password required: true placeholder: Password placeholder_expression: false order: 0 - identifiers: - field_key: password_repeat - label: Password (repeat) + name: default-enrollment-field-password-repeat id: prompt-field-password-repeat model: authentik_stages_prompt.prompt attrs: + field_key: password_repeat + label: Password (repeat) type: password required: true placeholder: Password (repeat) placeholder_expression: false order: 1 - identifiers: - field_key: name - label: Name + name: default-enrollment-field-name id: prompt-field-name model: authentik_stages_prompt.prompt attrs: + field_key: name + label: Name type: text required: true placeholder: Name placeholder_expression: false order: 0 - identifiers: - field_key: email - label: Email + name: default-enrollment-field-email id: prompt-field-email model: authentik_stages_prompt.prompt attrs: + field_key: email + label: Email type: email required: true placeholder: Email diff --git a/blueprints/example/flows-recovery-email-verification.yaml b/blueprints/example/flows-recovery-email-verification.yaml index f49d9ceaf..13e0da8aa 100644 --- a/blueprints/example/flows-recovery-email-verification.yaml +++ b/blueprints/example/flows-recovery-email-verification.yaml @@ -14,22 +14,24 @@ entries: designation: recovery authentication: require_unauthenticated - identifiers: - field_key: password - label: Password + name: default-recovery-field-password id: prompt-field-password model: authentik_stages_prompt.prompt attrs: + field_key: password + label: Password type: password required: true placeholder: Password order: 0 placeholder_expression: false - identifiers: - field_key: password_repeat - label: Password (repeat) + name: default-recovery-field-password-repeat id: prompt-field-password-repeat model: authentik_stages_prompt.prompt attrs: + field_key: password_repeat + label: Password (repeat) type: password required: true placeholder: Password (repeat) diff --git a/blueprints/migrations/migrate-prompt-name.yaml b/blueprints/migrations/migrate-prompt-name.yaml new file mode 100644 index 000000000..65724df11 --- /dev/null +++ b/blueprints/migrations/migrate-prompt-name.yaml @@ -0,0 +1,70 @@ +version: 1 +metadata: + labels: + blueprints.goauthentik.io/description: Migrate to 2023.2, remove unused prompt fields + name: Migration - Remove old prompt fields +entries: + - model: authentik_stages_prompt.prompt + identifiers: + name: admin_email_stage-default-oobe-password + attrs: + field_key: foo + label: foo + type: text + state: absent + - model: authentik_stages_prompt.prompt + identifiers: + name: attributes.settings.locale_default-user-settings + attrs: + field_key: foo + label: foo + type: text + state: absent + - model: authentik_stages_prompt.prompt + identifiers: + name: email_default-user-settings + attrs: + field_key: foo + label: foo + type: text + state: absent + - model: authentik_stages_prompt.prompt + identifiers: + name: name_default-user-settings + attrs: + field_key: foo + label: foo + type: text + state: absent + - model: authentik_stages_prompt.prompt + identifiers: + name: oobe-header-text_stage-default-oobe-password + attrs: + field_key: foo + label: foo + type: text + state: absent + - model: authentik_stages_prompt.prompt + identifiers: + name: password_default-password-change-prompt + attrs: + field_key: foo + label: foo + type: text + state: absent + - model: authentik_stages_prompt.prompt + identifiers: + name: password_repeat_default-password-change-prompt + attrs: + field_key: foo + label: foo + type: text + state: absent + - model: authentik_stages_prompt.prompt + identifiers: + name: username_default-source-enrollment-prompt + attrs: + field_key: foo + label: foo + type: text + state: absent diff --git a/schema.yml b/schema.yml index 45dcfbed1..30e9bc012 100644 --- a/schema.yml +++ b/schema.yml @@ -23008,6 +23008,10 @@ paths: name: label schema: type: string + - in: query + name: name + schema: + type: string - name: ordering required: false in: query @@ -34263,6 +34267,9 @@ components: type: object description: Prompt Serializer properties: + name: + type: string + minLength: 1 field_key: type: string minLength: 1 @@ -35278,6 +35285,8 @@ components: format: uuid readOnly: true title: Prompt uuid + name: + type: string field_key: type: string description: Name of the form field, also used to store the value @@ -35304,6 +35313,7 @@ components: required: - field_key - label + - name - pk - type PromptChallenge: @@ -35345,6 +35355,9 @@ components: type: object description: Prompt Serializer properties: + name: + type: string + minLength: 1 field_key: type: string minLength: 1 @@ -35373,6 +35386,7 @@ components: required: - field_key - label + - name - type PromptStage: type: object diff --git a/tests/e2e/test_flows_authenticators.py b/tests/e2e/test_flows_authenticators.py index fba64329e..58754b791 100644 --- a/tests/e2e/test_flows_authenticators.py +++ b/tests/e2e/test_flows_authenticators.py @@ -26,8 +26,8 @@ class TestFlowsAuthenticator(SeleniumTestCase): @retry() @apply_blueprint( - "default/10-flow-default-authentication-flow.yaml", - "default/10-flow-default-invalidation-flow.yaml", + "default/flow-default-authentication-flow.yaml", + "default/flow-default-invalidation-flow.yaml", ) def test_totp_validate(self): """test flow with otp stages""" @@ -52,10 +52,10 @@ class TestFlowsAuthenticator(SeleniumTestCase): @retry() @apply_blueprint( - "default/10-flow-default-authentication-flow.yaml", - "default/10-flow-default-invalidation-flow.yaml", + "default/flow-default-authentication-flow.yaml", + "default/flow-default-invalidation-flow.yaml", ) - @apply_blueprint("default/20-flow-default-authenticator-totp-setup.yaml") + @apply_blueprint("default/flow-default-authenticator-totp-setup.yaml") def test_totp_setup(self): """test TOTP Setup stage""" flow: Flow = Flow.objects.get(slug="default-authentication-flow") @@ -98,10 +98,10 @@ class TestFlowsAuthenticator(SeleniumTestCase): @retry() @apply_blueprint( - "default/10-flow-default-authentication-flow.yaml", - "default/10-flow-default-invalidation-flow.yaml", + "default/flow-default-authentication-flow.yaml", + "default/flow-default-invalidation-flow.yaml", ) - @apply_blueprint("default/20-flow-default-authenticator-static-setup.yaml") + @apply_blueprint("default/flow-default-authenticator-static-setup.yaml") def test_static_setup(self): """test Static OTP Setup stage""" flow: Flow = Flow.objects.get(slug="default-authentication-flow") diff --git a/tests/e2e/test_flows_enroll.py b/tests/e2e/test_flows_enroll.py index b0457c865..9e5880952 100644 --- a/tests/e2e/test_flows_enroll.py +++ b/tests/e2e/test_flows_enroll.py @@ -41,19 +41,28 @@ class TestFlowsEnroll(SeleniumTestCase): @retry() @apply_blueprint( - "default/10-flow-default-authentication-flow.yaml", - "default/10-flow-default-invalidation-flow.yaml", + "default/flow-default-authentication-flow.yaml", + "default/flow-default-invalidation-flow.yaml", ) def test_enroll_2_step(self): """Test 2-step enroll flow""" # First stage fields username_prompt = Prompt.objects.create( - field_key="username", label="Username", order=0, type=FieldTypes.TEXT + name=generate_id(), + field_key="username", + label="Username", + order=0, + type=FieldTypes.TEXT, ) password = Prompt.objects.create( - field_key="password", label="Password", order=1, type=FieldTypes.PASSWORD + name=generate_id(), + field_key="password", + label="Password", + order=1, + type=FieldTypes.PASSWORD, ) password_repeat = Prompt.objects.create( + name=generate_id(), field_key="password_repeat", label="Password (repeat)", order=2, @@ -62,10 +71,10 @@ class TestFlowsEnroll(SeleniumTestCase): # Second stage fields name_field = Prompt.objects.create( - field_key="name", label="Name", order=0, type=FieldTypes.TEXT + name=generate_id(), field_key="name", label="Name", order=0, type=FieldTypes.TEXT ) email = Prompt.objects.create( - field_key="email", label="E-Mail", order=1, type=FieldTypes.EMAIL + name=generate_id(), field_key="email", label="E-Mail", order=1, type=FieldTypes.EMAIL ) # Stages @@ -107,19 +116,28 @@ class TestFlowsEnroll(SeleniumTestCase): @retry() @apply_blueprint( - "default/10-flow-default-authentication-flow.yaml", - "default/10-flow-default-invalidation-flow.yaml", + "default/flow-default-authentication-flow.yaml", + "default/flow-default-invalidation-flow.yaml", ) def test_enroll_email(self): """Test enroll with Email verification""" # First stage fields username_prompt = Prompt.objects.create( - field_key="username", label="Username", order=0, type=FieldTypes.TEXT + name=generate_id(), + field_key="username", + label="Username", + order=0, + type=FieldTypes.TEXT, ) password = Prompt.objects.create( - field_key="password", label="Password", order=1, type=FieldTypes.PASSWORD + name=generate_id(), + field_key="password", + label="Password", + order=1, + type=FieldTypes.PASSWORD, ) password_repeat = Prompt.objects.create( + name=generate_id(), field_key="password_repeat", label="Password (repeat)", order=2, @@ -128,10 +146,10 @@ class TestFlowsEnroll(SeleniumTestCase): # Second stage fields name_field = Prompt.objects.create( - field_key="name", label="Name", order=0, type=FieldTypes.TEXT + name=generate_id(), field_key="name", label="Name", order=0, type=FieldTypes.TEXT ) email = Prompt.objects.create( - field_key="email", label="E-Mail", order=1, type=FieldTypes.EMAIL + name=generate_id(), field_key="email", label="E-Mail", order=1, type=FieldTypes.EMAIL ) # Stages diff --git a/tests/e2e/test_flows_login.py b/tests/e2e/test_flows_login.py index 69bb50f9f..194c27b53 100644 --- a/tests/e2e/test_flows_login.py +++ b/tests/e2e/test_flows_login.py @@ -12,8 +12,8 @@ class TestFlowsLogin(SeleniumTestCase): @retry() @apply_blueprint( - "default/10-flow-default-authentication-flow.yaml", - "default/10-flow-default-invalidation-flow.yaml", + "default/flow-default-authentication-flow.yaml", + "default/flow-default-invalidation-flow.yaml", ) def test_login(self): """test default login flow""" diff --git a/tests/e2e/test_flows_stage_setup.py b/tests/e2e/test_flows_stage_setup.py index 1dc991c6e..b33630dab 100644 --- a/tests/e2e/test_flows_stage_setup.py +++ b/tests/e2e/test_flows_stage_setup.py @@ -18,10 +18,10 @@ class TestFlowsStageSetup(SeleniumTestCase): """test stage setup flows""" @retry() - @apply_blueprint("default/0-flow-password-change.yaml") + @apply_blueprint("default/flow-password-change.yaml") @apply_blueprint( - "default/10-flow-default-authentication-flow.yaml", - "default/10-flow-default-invalidation-flow.yaml", + "default/flow-default-authentication-flow.yaml", + "default/flow-default-invalidation-flow.yaml", ) def test_password_change(self): """test password change flow""" diff --git a/tests/e2e/test_provider_ldap.py b/tests/e2e/test_provider_ldap.py index cc4dce79a..c76b7d38b 100644 --- a/tests/e2e/test_provider_ldap.py +++ b/tests/e2e/test_provider_ldap.py @@ -81,8 +81,8 @@ class TestProviderLDAP(SeleniumTestCase): @retry() @apply_blueprint( - "default/10-flow-default-authentication-flow.yaml", - "default/10-flow-default-invalidation-flow.yaml", + "default/flow-default-authentication-flow.yaml", + "default/flow-default-invalidation-flow.yaml", ) def test_ldap_bind_success(self): """Test simple bind""" @@ -108,8 +108,8 @@ class TestProviderLDAP(SeleniumTestCase): @retry() @apply_blueprint( - "default/10-flow-default-authentication-flow.yaml", - "default/10-flow-default-invalidation-flow.yaml", + "default/flow-default-authentication-flow.yaml", + "default/flow-default-invalidation-flow.yaml", ) def test_ldap_bind_success_ssl(self): """Test simple bind with ssl""" @@ -135,8 +135,8 @@ class TestProviderLDAP(SeleniumTestCase): @retry() @apply_blueprint( - "default/10-flow-default-authentication-flow.yaml", - "default/10-flow-default-invalidation-flow.yaml", + "default/flow-default-authentication-flow.yaml", + "default/flow-default-invalidation-flow.yaml", ) def test_ldap_bind_fail(self): """Test simple bind (failed)""" @@ -160,8 +160,8 @@ class TestProviderLDAP(SeleniumTestCase): @retry() @apply_blueprint( - "default/10-flow-default-authentication-flow.yaml", - "default/10-flow-default-invalidation-flow.yaml", + "default/flow-default-authentication-flow.yaml", + "default/flow-default-invalidation-flow.yaml", ) @reconcile_app("authentik_outposts") def test_ldap_bind_search(self): diff --git a/tests/e2e/test_provider_oauth2_github.py b/tests/e2e/test_provider_oauth2_github.py index b71e32063..9d0cf6253 100644 --- a/tests/e2e/test_provider_oauth2_github.py +++ b/tests/e2e/test_provider_oauth2_github.py @@ -58,12 +58,12 @@ class TestProviderOAuth2Github(SeleniumTestCase): @retry() @apply_blueprint( - "default/10-flow-default-authentication-flow.yaml", - "default/10-flow-default-invalidation-flow.yaml", + "default/flow-default-authentication-flow.yaml", + "default/flow-default-invalidation-flow.yaml", ) @apply_blueprint( - "default/20-flow-default-provider-authorization-explicit-consent.yaml", - "default/20-flow-default-provider-authorization-implicit-consent.yaml", + "default/flow-default-provider-authorization-explicit-consent.yaml", + "default/flow-default-provider-authorization-implicit-consent.yaml", ) @apply_blueprint( "system/providers-oauth2.yaml", @@ -114,12 +114,12 @@ class TestProviderOAuth2Github(SeleniumTestCase): @retry() @apply_blueprint( - "default/10-flow-default-authentication-flow.yaml", - "default/10-flow-default-invalidation-flow.yaml", + "default/flow-default-authentication-flow.yaml", + "default/flow-default-invalidation-flow.yaml", ) @apply_blueprint( - "default/20-flow-default-provider-authorization-explicit-consent.yaml", - "default/20-flow-default-provider-authorization-implicit-consent.yaml", + "default/flow-default-provider-authorization-explicit-consent.yaml", + "default/flow-default-provider-authorization-implicit-consent.yaml", ) @apply_blueprint( "system/providers-oauth2.yaml", @@ -189,12 +189,12 @@ class TestProviderOAuth2Github(SeleniumTestCase): @retry() @apply_blueprint( - "default/10-flow-default-authentication-flow.yaml", - "default/10-flow-default-invalidation-flow.yaml", + "default/flow-default-authentication-flow.yaml", + "default/flow-default-invalidation-flow.yaml", ) @apply_blueprint( - "default/20-flow-default-provider-authorization-explicit-consent.yaml", - "default/20-flow-default-provider-authorization-implicit-consent.yaml", + "default/flow-default-provider-authorization-explicit-consent.yaml", + "default/flow-default-provider-authorization-implicit-consent.yaml", ) @reconcile_app("authentik_crypto") def test_denied(self): diff --git a/tests/e2e/test_provider_oauth2_grafana.py b/tests/e2e/test_provider_oauth2_grafana.py index 80ebe41e2..baa930daa 100644 --- a/tests/e2e/test_provider_oauth2_grafana.py +++ b/tests/e2e/test_provider_oauth2_grafana.py @@ -67,12 +67,12 @@ class TestProviderOAuth2OAuth(SeleniumTestCase): @retry() @apply_blueprint( - "default/10-flow-default-authentication-flow.yaml", - "default/10-flow-default-invalidation-flow.yaml", + "default/flow-default-authentication-flow.yaml", + "default/flow-default-invalidation-flow.yaml", ) @apply_blueprint( - "default/20-flow-default-provider-authorization-explicit-consent.yaml", - "default/20-flow-default-provider-authorization-implicit-consent.yaml", + "default/flow-default-provider-authorization-explicit-consent.yaml", + "default/flow-default-provider-authorization-implicit-consent.yaml", ) @apply_blueprint( "system/providers-oauth2.yaml", @@ -116,12 +116,12 @@ class TestProviderOAuth2OAuth(SeleniumTestCase): @retry() @apply_blueprint( - "default/10-flow-default-authentication-flow.yaml", - "default/10-flow-default-invalidation-flow.yaml", + "default/flow-default-authentication-flow.yaml", + "default/flow-default-invalidation-flow.yaml", ) @apply_blueprint( - "default/20-flow-default-provider-authorization-explicit-consent.yaml", - "default/20-flow-default-provider-authorization-implicit-consent.yaml", + "default/flow-default-provider-authorization-explicit-consent.yaml", + "default/flow-default-provider-authorization-implicit-consent.yaml", ) @apply_blueprint( "system/providers-oauth2.yaml", @@ -178,12 +178,12 @@ class TestProviderOAuth2OAuth(SeleniumTestCase): @retry() @apply_blueprint( - "default/10-flow-default-authentication-flow.yaml", - "default/10-flow-default-invalidation-flow.yaml", + "default/flow-default-authentication-flow.yaml", + "default/flow-default-invalidation-flow.yaml", ) @apply_blueprint( - "default/20-flow-default-provider-authorization-explicit-consent.yaml", - "default/20-flow-default-provider-authorization-implicit-consent.yaml", + "default/flow-default-provider-authorization-explicit-consent.yaml", + "default/flow-default-provider-authorization-implicit-consent.yaml", ) @apply_blueprint( "system/providers-oauth2.yaml", @@ -249,12 +249,12 @@ class TestProviderOAuth2OAuth(SeleniumTestCase): @retry() @apply_blueprint( - "default/10-flow-default-authentication-flow.yaml", - "default/10-flow-default-invalidation-flow.yaml", + "default/flow-default-authentication-flow.yaml", + "default/flow-default-invalidation-flow.yaml", ) @apply_blueprint( - "default/20-flow-default-provider-authorization-explicit-consent.yaml", - "default/20-flow-default-provider-authorization-implicit-consent.yaml", + "default/flow-default-provider-authorization-explicit-consent.yaml", + "default/flow-default-provider-authorization-implicit-consent.yaml", ) @apply_blueprint( "system/providers-oauth2.yaml", @@ -329,12 +329,12 @@ class TestProviderOAuth2OAuth(SeleniumTestCase): @retry() @apply_blueprint( - "default/10-flow-default-authentication-flow.yaml", - "default/10-flow-default-invalidation-flow.yaml", + "default/flow-default-authentication-flow.yaml", + "default/flow-default-invalidation-flow.yaml", ) @apply_blueprint( - "default/20-flow-default-provider-authorization-explicit-consent.yaml", - "default/20-flow-default-provider-authorization-implicit-consent.yaml", + "default/flow-default-provider-authorization-explicit-consent.yaml", + "default/flow-default-provider-authorization-implicit-consent.yaml", ) @apply_blueprint( "system/providers-oauth2.yaml", diff --git a/tests/e2e/test_provider_oidc.py b/tests/e2e/test_provider_oidc.py index 2bda268ec..3af2f4f09 100644 --- a/tests/e2e/test_provider_oidc.py +++ b/tests/e2e/test_provider_oidc.py @@ -65,12 +65,12 @@ class TestProviderOAuth2OIDC(SeleniumTestCase): @retry() @apply_blueprint( - "default/10-flow-default-authentication-flow.yaml", - "default/10-flow-default-invalidation-flow.yaml", + "default/flow-default-authentication-flow.yaml", + "default/flow-default-invalidation-flow.yaml", ) @apply_blueprint( - "default/20-flow-default-provider-authorization-explicit-consent.yaml", - "default/20-flow-default-provider-authorization-implicit-consent.yaml", + "default/flow-default-provider-authorization-explicit-consent.yaml", + "default/flow-default-provider-authorization-implicit-consent.yaml", ) @reconcile_app("authentik_crypto") def test_redirect_uri_error(self): @@ -111,12 +111,12 @@ class TestProviderOAuth2OIDC(SeleniumTestCase): @retry() @apply_blueprint( - "default/10-flow-default-authentication-flow.yaml", - "default/10-flow-default-invalidation-flow.yaml", + "default/flow-default-authentication-flow.yaml", + "default/flow-default-invalidation-flow.yaml", ) @apply_blueprint( - "default/20-flow-default-provider-authorization-explicit-consent.yaml", - "default/20-flow-default-provider-authorization-implicit-consent.yaml", + "default/flow-default-provider-authorization-explicit-consent.yaml", + "default/flow-default-provider-authorization-implicit-consent.yaml", ) @reconcile_app("authentik_crypto") @apply_blueprint("system/providers-oauth2.yaml") @@ -166,12 +166,12 @@ class TestProviderOAuth2OIDC(SeleniumTestCase): @retry() @apply_blueprint( - "default/10-flow-default-authentication-flow.yaml", - "default/10-flow-default-invalidation-flow.yaml", + "default/flow-default-authentication-flow.yaml", + "default/flow-default-invalidation-flow.yaml", ) @apply_blueprint( - "default/20-flow-default-provider-authorization-explicit-consent.yaml", - "default/20-flow-default-provider-authorization-implicit-consent.yaml", + "default/flow-default-provider-authorization-explicit-consent.yaml", + "default/flow-default-provider-authorization-implicit-consent.yaml", ) @reconcile_app("authentik_crypto") @apply_blueprint("system/providers-oauth2.yaml") @@ -236,12 +236,12 @@ class TestProviderOAuth2OIDC(SeleniumTestCase): @retry() @apply_blueprint( - "default/10-flow-default-authentication-flow.yaml", - "default/10-flow-default-invalidation-flow.yaml", + "default/flow-default-authentication-flow.yaml", + "default/flow-default-invalidation-flow.yaml", ) @apply_blueprint( - "default/20-flow-default-provider-authorization-explicit-consent.yaml", - "default/20-flow-default-provider-authorization-implicit-consent.yaml", + "default/flow-default-provider-authorization-explicit-consent.yaml", + "default/flow-default-provider-authorization-implicit-consent.yaml", ) @reconcile_app("authentik_crypto") def test_authorization_denied(self): diff --git a/tests/e2e/test_provider_oidc_implicit.py b/tests/e2e/test_provider_oidc_implicit.py index dc4df2b95..a130acbe6 100644 --- a/tests/e2e/test_provider_oidc_implicit.py +++ b/tests/e2e/test_provider_oidc_implicit.py @@ -65,12 +65,12 @@ class TestProviderOAuth2OIDCImplicit(SeleniumTestCase): @retry() @apply_blueprint( - "default/10-flow-default-authentication-flow.yaml", - "default/10-flow-default-invalidation-flow.yaml", + "default/flow-default-authentication-flow.yaml", + "default/flow-default-invalidation-flow.yaml", ) @apply_blueprint( - "default/20-flow-default-provider-authorization-explicit-consent.yaml", - "default/20-flow-default-provider-authorization-implicit-consent.yaml", + "default/flow-default-provider-authorization-explicit-consent.yaml", + "default/flow-default-provider-authorization-implicit-consent.yaml", ) @reconcile_app("authentik_crypto") def test_redirect_uri_error(self): @@ -111,12 +111,12 @@ class TestProviderOAuth2OIDCImplicit(SeleniumTestCase): @retry() @apply_blueprint( - "default/10-flow-default-authentication-flow.yaml", - "default/10-flow-default-invalidation-flow.yaml", + "default/flow-default-authentication-flow.yaml", + "default/flow-default-invalidation-flow.yaml", ) @apply_blueprint( - "default/20-flow-default-provider-authorization-explicit-consent.yaml", - "default/20-flow-default-provider-authorization-implicit-consent.yaml", + "default/flow-default-provider-authorization-explicit-consent.yaml", + "default/flow-default-provider-authorization-implicit-consent.yaml", ) @reconcile_app("authentik_crypto") @apply_blueprint("system/providers-oauth2.yaml") @@ -161,12 +161,12 @@ class TestProviderOAuth2OIDCImplicit(SeleniumTestCase): @retry() @apply_blueprint( - "default/10-flow-default-authentication-flow.yaml", - "default/10-flow-default-invalidation-flow.yaml", + "default/flow-default-authentication-flow.yaml", + "default/flow-default-invalidation-flow.yaml", ) @apply_blueprint( - "default/20-flow-default-provider-authorization-explicit-consent.yaml", - "default/20-flow-default-provider-authorization-implicit-consent.yaml", + "default/flow-default-provider-authorization-explicit-consent.yaml", + "default/flow-default-provider-authorization-implicit-consent.yaml", ) @reconcile_app("authentik_crypto") @apply_blueprint("system/providers-oauth2.yaml") @@ -227,12 +227,12 @@ class TestProviderOAuth2OIDCImplicit(SeleniumTestCase): @retry() @apply_blueprint( - "default/10-flow-default-authentication-flow.yaml", - "default/10-flow-default-invalidation-flow.yaml", + "default/flow-default-authentication-flow.yaml", + "default/flow-default-invalidation-flow.yaml", ) @apply_blueprint( - "default/20-flow-default-provider-authorization-explicit-consent.yaml", - "default/20-flow-default-provider-authorization-implicit-consent.yaml", + "default/flow-default-provider-authorization-explicit-consent.yaml", + "default/flow-default-provider-authorization-implicit-consent.yaml", ) @reconcile_app("authentik_crypto") def test_authorization_denied(self): diff --git a/tests/e2e/test_provider_proxy.py b/tests/e2e/test_provider_proxy.py index 7ea0bf359..e2f883279 100644 --- a/tests/e2e/test_provider_proxy.py +++ b/tests/e2e/test_provider_proxy.py @@ -57,12 +57,12 @@ class TestProviderProxy(SeleniumTestCase): @retry() @apply_blueprint( - "default/10-flow-default-authentication-flow.yaml", - "default/10-flow-default-invalidation-flow.yaml", + "default/flow-default-authentication-flow.yaml", + "default/flow-default-invalidation-flow.yaml", ) @apply_blueprint( - "default/20-flow-default-provider-authorization-explicit-consent.yaml", - "default/20-flow-default-provider-authorization-implicit-consent.yaml", + "default/flow-default-provider-authorization-explicit-consent.yaml", + "default/flow-default-provider-authorization-implicit-consent.yaml", ) @apply_blueprint( "system/providers-oauth2.yaml", @@ -123,12 +123,12 @@ class TestProviderProxy(SeleniumTestCase): @retry() @apply_blueprint( - "default/10-flow-default-authentication-flow.yaml", - "default/10-flow-default-invalidation-flow.yaml", + "default/flow-default-authentication-flow.yaml", + "default/flow-default-invalidation-flow.yaml", ) @apply_blueprint( - "default/20-flow-default-provider-authorization-explicit-consent.yaml", - "default/20-flow-default-provider-authorization-implicit-consent.yaml", + "default/flow-default-provider-authorization-explicit-consent.yaml", + "default/flow-default-provider-authorization-implicit-consent.yaml", ) @apply_blueprint( "system/providers-oauth2.yaml", @@ -200,12 +200,12 @@ class TestProviderProxyConnect(ChannelsLiveServerTestCase): @retry() @apply_blueprint( - "default/10-flow-default-authentication-flow.yaml", - "default/10-flow-default-invalidation-flow.yaml", + "default/flow-default-authentication-flow.yaml", + "default/flow-default-invalidation-flow.yaml", ) @apply_blueprint( - "default/20-flow-default-provider-authorization-explicit-consent.yaml", - "default/20-flow-default-provider-authorization-implicit-consent.yaml", + "default/flow-default-provider-authorization-explicit-consent.yaml", + "default/flow-default-provider-authorization-implicit-consent.yaml", ) @reconcile_app("authentik_crypto") def test_proxy_connectivity(self): diff --git a/tests/e2e/test_provider_saml.py b/tests/e2e/test_provider_saml.py index 8f5dffd0b..8be60fe19 100644 --- a/tests/e2e/test_provider_saml.py +++ b/tests/e2e/test_provider_saml.py @@ -64,12 +64,12 @@ class TestProviderSAML(SeleniumTestCase): @retry() @apply_blueprint( - "default/10-flow-default-authentication-flow.yaml", - "default/10-flow-default-invalidation-flow.yaml", + "default/flow-default-authentication-flow.yaml", + "default/flow-default-invalidation-flow.yaml", ) @apply_blueprint( - "default/20-flow-default-provider-authorization-explicit-consent.yaml", - "default/20-flow-default-provider-authorization-implicit-consent.yaml", + "default/flow-default-provider-authorization-explicit-consent.yaml", + "default/flow-default-provider-authorization-implicit-consent.yaml", ) @apply_blueprint( "system/providers-saml.yaml", @@ -133,12 +133,12 @@ class TestProviderSAML(SeleniumTestCase): @retry() @apply_blueprint( - "default/10-flow-default-authentication-flow.yaml", - "default/10-flow-default-invalidation-flow.yaml", + "default/flow-default-authentication-flow.yaml", + "default/flow-default-invalidation-flow.yaml", ) @apply_blueprint( - "default/20-flow-default-provider-authorization-explicit-consent.yaml", - "default/20-flow-default-provider-authorization-implicit-consent.yaml", + "default/flow-default-provider-authorization-explicit-consent.yaml", + "default/flow-default-provider-authorization-implicit-consent.yaml", ) @apply_blueprint( "system/providers-saml.yaml", @@ -217,12 +217,12 @@ class TestProviderSAML(SeleniumTestCase): @retry() @apply_blueprint( - "default/10-flow-default-authentication-flow.yaml", - "default/10-flow-default-invalidation-flow.yaml", + "default/flow-default-authentication-flow.yaml", + "default/flow-default-invalidation-flow.yaml", ) @apply_blueprint( - "default/20-flow-default-provider-authorization-explicit-consent.yaml", - "default/20-flow-default-provider-authorization-implicit-consent.yaml", + "default/flow-default-provider-authorization-explicit-consent.yaml", + "default/flow-default-provider-authorization-implicit-consent.yaml", ) @apply_blueprint( "system/providers-saml.yaml", @@ -301,12 +301,12 @@ class TestProviderSAML(SeleniumTestCase): @retry() @apply_blueprint( - "default/10-flow-default-authentication-flow.yaml", - "default/10-flow-default-invalidation-flow.yaml", + "default/flow-default-authentication-flow.yaml", + "default/flow-default-invalidation-flow.yaml", ) @apply_blueprint( - "default/20-flow-default-provider-authorization-explicit-consent.yaml", - "default/20-flow-default-provider-authorization-implicit-consent.yaml", + "default/flow-default-provider-authorization-explicit-consent.yaml", + "default/flow-default-provider-authorization-implicit-consent.yaml", ) @apply_blueprint( "system/providers-saml.yaml", @@ -376,12 +376,12 @@ class TestProviderSAML(SeleniumTestCase): @retry() @apply_blueprint( - "default/10-flow-default-authentication-flow.yaml", - "default/10-flow-default-invalidation-flow.yaml", + "default/flow-default-authentication-flow.yaml", + "default/flow-default-invalidation-flow.yaml", ) @apply_blueprint( - "default/20-flow-default-provider-authorization-explicit-consent.yaml", - "default/20-flow-default-provider-authorization-implicit-consent.yaml", + "default/flow-default-provider-authorization-explicit-consent.yaml", + "default/flow-default-provider-authorization-implicit-consent.yaml", ) @apply_blueprint( "system/providers-saml.yaml", @@ -425,12 +425,12 @@ class TestProviderSAML(SeleniumTestCase): @retry() @apply_blueprint( - "default/10-flow-default-authentication-flow.yaml", - "default/10-flow-default-invalidation-flow.yaml", + "default/flow-default-authentication-flow.yaml", + "default/flow-default-invalidation-flow.yaml", ) @apply_blueprint( - "default/20-flow-default-provider-authorization-explicit-consent.yaml", - "default/20-flow-default-provider-authorization-implicit-consent.yaml", + "default/flow-default-provider-authorization-explicit-consent.yaml", + "default/flow-default-provider-authorization-implicit-consent.yaml", ) @apply_blueprint( "system/providers-saml.yaml", diff --git a/tests/e2e/test_source_oauth.py b/tests/e2e/test_source_oauth.py index 868d69fae..00acbee20 100644 --- a/tests/e2e/test_source_oauth.py +++ b/tests/e2e/test_source_oauth.py @@ -143,17 +143,17 @@ class TestSourceOAuth2(SeleniumTestCase): @retry() @apply_blueprint( - "default/10-flow-default-authentication-flow.yaml", - "default/10-flow-default-invalidation-flow.yaml", + "default/flow-default-authentication-flow.yaml", + "default/flow-default-invalidation-flow.yaml", ) @apply_blueprint( - "default/20-flow-default-provider-authorization-explicit-consent.yaml", - "default/20-flow-default-provider-authorization-implicit-consent.yaml", + "default/flow-default-provider-authorization-explicit-consent.yaml", + "default/flow-default-provider-authorization-implicit-consent.yaml", ) @apply_blueprint( - "default/20-flow-default-source-authentication.yaml", - "default/20-flow-default-source-enrollment.yaml", - "default/20-flow-default-source-pre-authentication.yaml", + "default/flow-default-source-authentication.yaml", + "default/flow-default-source-enrollment.yaml", + "default/flow-default-source-pre-authentication.yaml", ) def test_oauth_enroll(self): """test OAuth Source With With OIDC""" @@ -200,12 +200,12 @@ class TestSourceOAuth2(SeleniumTestCase): @retry() @apply_blueprint( - "default/10-flow-default-authentication-flow.yaml", - "default/10-flow-default-invalidation-flow.yaml", + "default/flow-default-authentication-flow.yaml", + "default/flow-default-invalidation-flow.yaml", ) @apply_blueprint( - "default/20-flow-default-provider-authorization-explicit-consent.yaml", - "default/20-flow-default-provider-authorization-implicit-consent.yaml", + "default/flow-default-provider-authorization-explicit-consent.yaml", + "default/flow-default-provider-authorization-implicit-consent.yaml", ) def test_oauth_enroll_auth(self): """test OAuth Source With With OIDC (enroll and authenticate again)""" @@ -292,13 +292,13 @@ class TestSourceOAuth1(SeleniumTestCase): @retry() @apply_blueprint( - "default/10-flow-default-authentication-flow.yaml", - "default/10-flow-default-invalidation-flow.yaml", + "default/flow-default-authentication-flow.yaml", + "default/flow-default-invalidation-flow.yaml", ) @apply_blueprint( - "default/20-flow-default-source-authentication.yaml", - "default/20-flow-default-source-enrollment.yaml", - "default/20-flow-default-source-pre-authentication.yaml", + "default/flow-default-source-authentication.yaml", + "default/flow-default-source-enrollment.yaml", + "default/flow-default-source-pre-authentication.yaml", ) def test_oauth_enroll(self): """test OAuth Source With With OIDC""" diff --git a/tests/e2e/test_source_saml.py b/tests/e2e/test_source_saml.py index d98a09a6a..ca3e0fa4d 100644 --- a/tests/e2e/test_source_saml.py +++ b/tests/e2e/test_source_saml.py @@ -96,13 +96,13 @@ class TestSourceSAML(SeleniumTestCase): @retry() @apply_blueprint( - "default/10-flow-default-authentication-flow.yaml", - "default/10-flow-default-invalidation-flow.yaml", + "default/flow-default-authentication-flow.yaml", + "default/flow-default-invalidation-flow.yaml", ) @apply_blueprint( - "default/20-flow-default-source-authentication.yaml", - "default/20-flow-default-source-enrollment.yaml", - "default/20-flow-default-source-pre-authentication.yaml", + "default/flow-default-source-authentication.yaml", + "default/flow-default-source-enrollment.yaml", + "default/flow-default-source-pre-authentication.yaml", ) def test_idp_redirect(self): """test SAML Source With redirect binding""" @@ -166,13 +166,13 @@ class TestSourceSAML(SeleniumTestCase): @retry() @apply_blueprint( - "default/10-flow-default-authentication-flow.yaml", - "default/10-flow-default-invalidation-flow.yaml", + "default/flow-default-authentication-flow.yaml", + "default/flow-default-invalidation-flow.yaml", ) @apply_blueprint( - "default/20-flow-default-source-authentication.yaml", - "default/20-flow-default-source-enrollment.yaml", - "default/20-flow-default-source-pre-authentication.yaml", + "default/flow-default-source-authentication.yaml", + "default/flow-default-source-enrollment.yaml", + "default/flow-default-source-pre-authentication.yaml", ) def test_idp_post(self): """test SAML Source With post binding""" @@ -249,13 +249,13 @@ class TestSourceSAML(SeleniumTestCase): @retry() @apply_blueprint( - "default/10-flow-default-authentication-flow.yaml", - "default/10-flow-default-invalidation-flow.yaml", + "default/flow-default-authentication-flow.yaml", + "default/flow-default-invalidation-flow.yaml", ) @apply_blueprint( - "default/20-flow-default-source-authentication.yaml", - "default/20-flow-default-source-enrollment.yaml", - "default/20-flow-default-source-pre-authentication.yaml", + "default/flow-default-source-authentication.yaml", + "default/flow-default-source-enrollment.yaml", + "default/flow-default-source-pre-authentication.yaml", ) def test_idp_post_auto(self): """test SAML Source With post binding (auto redirect)""" diff --git a/web/src/admin/blueprints/BlueprintListPage.ts b/web/src/admin/blueprints/BlueprintListPage.ts index 0e958f071..fe673a980 100644 --- a/web/src/admin/blueprints/BlueprintListPage.ts +++ b/web/src/admin/blueprints/BlueprintListPage.ts @@ -13,9 +13,11 @@ import { TablePage } from "@goauthentik/elements/table/TablePage"; import { t } from "@lingui/macro"; -import { TemplateResult, html } from "lit"; +import { CSSResult, TemplateResult, html } from "lit"; import { customElement, property } from "lit/decorators.js"; +import PFDescriptionList from "@patternfly/patternfly/components/DescriptionList/description-list.css"; + import { BlueprintInstance, BlueprintInstanceStatusEnum, ManagedApi } from "@goauthentik/api"; export function BlueprintStatus(blueprint?: BlueprintInstance): string { @@ -32,6 +34,7 @@ export function BlueprintStatus(blueprint?: BlueprintInstance): string { } return t`Unknown`; } + @customElement("ak-blueprint-list") export class BlueprintListPage extends TablePage { searchEnabled(): boolean { @@ -47,11 +50,16 @@ export class BlueprintListPage extends TablePage { return "pf-icon pf-icon-blueprint"; } + expandable = true; checkbox = true; @property() order = "name"; + static get styles(): CSSResult[] { + return super.styles.concat(PFDescriptionList); + } + async apiEndpoint(page: number): Promise> { return new ManagedApi(DEFAULT_CONFIG).managedBlueprintsList({ ordering: this.order, @@ -96,9 +104,34 @@ export class BlueprintListPage extends TablePage { `; } + renderExpanded(item: BlueprintInstance): TemplateResult { + return html` +
+
+
+
+ ${t`Path`} +
+
+
+
${item.path}
+
+
+
+
+
+ `; + } + row(item: BlueprintInstance): TemplateResult[] { + let description = undefined; + const descKey = "blueprints.goauthentik.io/description"; + if (Object.hasOwn(item.metadata.labels, descKey)) { + description = item.metadata.labels[descKey]; + } return [ - html`${item.name}`, + html`
${item.name}
+ ${description ? html`${description}` : html``}`, html`${BlueprintStatus(item)}`, html`${item.lastApplied.toLocaleString()}`, html` diff --git a/web/src/admin/stages/prompt/PromptForm.ts b/web/src/admin/stages/prompt/PromptForm.ts index 8a9083dda..efbbf9edb 100644 --- a/web/src/admin/stages/prompt/PromptForm.ts +++ b/web/src/admin/stages/prompt/PromptForm.ts @@ -132,6 +132,17 @@ export class PromptForm extends ModelForm { renderForm(): TemplateResult { return html`
+ + +

+ ${t`Unique name of this field, used for selecting fields in prompt stages.`} +

+
{ checkbox = true; @property() - order = "order"; + order = "name"; async apiEndpoint(page: number): Promise> { return new StagesApi(DEFAULT_CONFIG).stagesPromptPromptsList({ @@ -48,8 +47,8 @@ export class PromptListPage extends TablePage { columns(): TableColumn[] { return [ + new TableColumn(t`Name`, "name"), new TableColumn(t`Field`, "field_key"), - new TableColumn(t`Label`, "label"), new TableColumn(t`Type`, "type"), new TableColumn(t`Order`, "order"), new TableColumn(t`Stages`), @@ -81,8 +80,8 @@ export class PromptListPage extends TablePage { row(item: Prompt): TemplateResult[] { return [ - html`${item.fieldKey}`, - html`${truncate(item.label, 20)}`, + html`${item.name}`, + html`${item.fieldKey}`, html`${item.type}`, html`${item.order}`, html`${item.promptstageSet?.map((stage) => { diff --git a/website/developer-docs/blueprints/index.md b/website/developer-docs/blueprints/index.md index bd7a653f3..0713fb9a0 100644 --- a/website/developer-docs/blueprints/index.md +++ b/website/developer-docs/blueprints/index.md @@ -34,6 +34,8 @@ Any additional `.yaml` file in `/blueprints` will be discovered and automaticall To disable existing blueprints, an empty file can be mounted over the existing blueprint. +File-based blueprints are automatically removed once they become unavailable, however none of the objects created by those blueprints afre affected by this. + ## Storage - OCI Blueprints can also be stored in remote [OCI](https://opencontainers.org/) compliant registries. This includes GitHub Container Registry, Docker hub and many other registries. diff --git a/website/developer-docs/blueprints/v1/structure.md b/website/developer-docs/blueprints/v1/structure.md index 78ebceb89..47394c817 100644 --- a/website/developer-docs/blueprints/v1/structure.md +++ b/website/developer-docs/blueprints/v1/structure.md @@ -60,3 +60,7 @@ Used by authentik's packaged blueprints to keep globals up-to-date. Should only #### `blueprints.goauthentik.io/instantiate`: Configure if this blueprint should automatically be instantiated (defaults to `"true"`). When set to `"false"`, blueprints are listed and available to be instantiated via API/Browser. + +#### `blueprints.goauthentik.io/description`: + +Optionally set a description, which can be seen in the web interface.