stages/prompt: field name (#4497)

* add prompt field name

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

* remove numerical prefix

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

* fix missing name

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

* use text field

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

* add description label

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

* add migrate blueprint to remove old stages

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

* add task to remove unretrievable blueprints

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

* lint

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

* fix blueprint test paths

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

* fix tests

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

* actually fix tests

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

* fix tests even more

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

* fix fixtures

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

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
This commit is contained in:
Jens L 2023-01-24 12:23:22 +01:00 committed by GitHub
parent 9437e2d3ab
commit 53b65a9d1a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
50 changed files with 468 additions and 219 deletions

View File

@ -57,9 +57,10 @@ class AuthentikBlueprintsConfig(ManagedAppConfig):
def reconcile_blueprints_discover(self): def reconcile_blueprints_discover(self):
"""Run blueprint discovery""" """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() blueprints_discover.delay()
clear_failed_blueprints.delay()
def import_models(self): def import_models(self):
super().import_models() super().import_models()

View File

@ -9,4 +9,9 @@ CELERY_BEAT_SCHEDULE = {
"schedule": crontab(minute=fqdn_rand("blueprints_v1_discover"), hour="*"), "schedule": crontab(minute=fqdn_rand("blueprints_v1_discover"), hour="*"),
"options": {"queue": "authentik_scheduled"}, "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"},
},
} }

View File

@ -4,6 +4,7 @@ entries:
pk: cb954fd4-65a5-4ad9-b1ee-180ee9559cf4 pk: cb954fd4-65a5-4ad9-b1ee-180ee9559cf4
model: authentik_stages_prompt.prompt model: authentik_stages_prompt.prompt
attrs: attrs:
name: qwerweqrq
field_key: username field_key: username
label: Username label: Username
type: username type: username

View File

@ -13,7 +13,7 @@ from authentik.tenants.models import Tenant
class TestPackaged(TransactionTestCase): class TestPackaged(TransactionTestCase):
"""Empty class, test methods are added dynamically""" """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): def test_decorator_static(self):
"""Test @apply_blueprint decorator""" """Test @apply_blueprint decorator"""
self.assertTrue(Tenant.objects.filter(domain="authentik-default").exists()) self.assertTrue(Tenant.objects.filter(domain="authentik-default").exists())

View File

@ -262,15 +262,21 @@ class TestBlueprintsV1(TransactionTestCase):
with transaction_rollback(): with transaction_rollback():
# First stage fields # First stage fields
username_prompt = Prompt.objects.create( 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( password = Prompt.objects.create(
name=generate_id(),
field_key="password", field_key="password",
label="Password", label="Password",
order=1, order=1,
type=FieldTypes.PASSWORD, type=FieldTypes.PASSWORD,
) )
password_repeat = Prompt.objects.create( password_repeat = Prompt.objects.create(
name=generate_id(),
field_key="password_repeat", field_key="password_repeat",
label="Password (repeat)", label="Password (repeat)",
order=2, order=2,

View File

@ -3,3 +3,4 @@
LABEL_AUTHENTIK_SYSTEM = "blueprints.goauthentik.io/system" LABEL_AUTHENTIK_SYSTEM = "blueprints.goauthentik.io/system"
LABEL_AUTHENTIK_INSTANTIATE = "blueprints.goauthentik.io/instantiate" LABEL_AUTHENTIK_INSTANTIATE = "blueprints.goauthentik.io/instantiate"
LABEL_AUTHENTIK_GENERATED = "blueprints.goauthentik.io/generated" LABEL_AUTHENTIK_GENERATED = "blueprints.goauthentik.io/generated"
LABEL_AUTHENTIK_DESCRIPTION = "blueprints.goauthentik.io/description"

View File

@ -219,3 +219,14 @@ def apply_blueprint(self: MonitoredTask, instance_pk: str):
finally: finally:
if instance: if instance:
instance.save() 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()

View File

@ -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.core.tests.utils import create_test_admin_user, create_test_flow
from authentik.flows.models import FlowDesignation, FlowStageBinding from authentik.flows.models import FlowDesignation, FlowStageBinding
from authentik.flows.tests import FlowTestCase from authentik.flows.tests import FlowTestCase
from authentik.lib.generators import generate_id
from authentik.policies.password.models import PasswordPolicy from authentik.policies.password.models import PasswordPolicy
from authentik.stages.prompt.models import FieldTypes, Prompt, PromptStage from authentik.stages.prompt.models import FieldTypes, Prompt, PromptStage
@ -16,6 +17,7 @@ class TestPasswordPolicyFlow(FlowTestCase):
self.flow = create_test_flow(FlowDesignation.AUTHENTICATION) self.flow = create_test_flow(FlowDesignation.AUTHENTICATION)
password_prompt = Prompt.objects.create( password_prompt = Prompt.objects.create(
name=generate_id(),
field_key="password", field_key="password",
label="PASSWORD_LABEL", label="PASSWORD_LABEL",
type=FieldTypes.PASSWORD, type=FieldTypes.PASSWORD,

View File

@ -42,6 +42,7 @@ class PromptSerializer(ModelSerializer):
model = Prompt model = Prompt
fields = [ fields = [
"pk", "pk",
"name",
"field_key", "field_key",
"label", "label",
"type", "type",
@ -59,5 +60,5 @@ class PromptViewSet(UsedByMixin, ModelViewSet):
queryset = Prompt.objects.all().prefetch_related("promptstage_set") queryset = Prompt.objects.all().prefetch_related("promptstage_set")
serializer_class = PromptSerializer serializer_class = PromptSerializer
filterset_fields = ["field_key", "label", "type", "placeholder"] filterset_fields = ["field_key", "name", "label", "type", "placeholder"]
search_fields = ["field_key", "label", "type", "placeholder"] search_fields = ["field_key", "name", "label", "type", "placeholder"]

View File

@ -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),
),
]

View File

@ -96,6 +96,7 @@ class Prompt(SerializerModel):
"""Single Prompt, part of a prompt stage.""" """Single Prompt, part of a prompt stage."""
prompt_uuid = models.UUIDField(primary_key=True, editable=False, default=uuid4) prompt_uuid = models.UUIDField(primary_key=True, editable=False, default=uuid4)
name = models.TextField(unique=True, blank=False)
field_key = models.TextField( field_key = models.TextField(
help_text=_("Name of the form field, also used to store the value") help_text=_("Name of the form field, also used to store the value")

View File

@ -30,6 +30,7 @@ class TestPromptStage(FlowTestCase):
self.factory = RequestFactory() self.factory = RequestFactory()
self.flow = create_test_flow() self.flow = create_test_flow()
username_prompt = Prompt.objects.create( username_prompt = Prompt.objects.create(
name=generate_id(),
field_key="username_prompt", field_key="username_prompt",
label="USERNAME_LABEL", label="USERNAME_LABEL",
type=FieldTypes.USERNAME, type=FieldTypes.USERNAME,
@ -37,6 +38,7 @@ class TestPromptStage(FlowTestCase):
placeholder="USERNAME_PLACEHOLDER", placeholder="USERNAME_PLACEHOLDER",
) )
text_prompt = Prompt.objects.create( text_prompt = Prompt.objects.create(
name=generate_id(),
field_key="text_prompt", field_key="text_prompt",
label="TEXT_LABEL", label="TEXT_LABEL",
type=FieldTypes.TEXT, type=FieldTypes.TEXT,
@ -44,6 +46,7 @@ class TestPromptStage(FlowTestCase):
placeholder="TEXT_PLACEHOLDER", placeholder="TEXT_PLACEHOLDER",
) )
email_prompt = Prompt.objects.create( email_prompt = Prompt.objects.create(
name=generate_id(),
field_key="email_prompt", field_key="email_prompt",
label="EMAIL_LABEL", label="EMAIL_LABEL",
type=FieldTypes.EMAIL, type=FieldTypes.EMAIL,
@ -51,6 +54,7 @@ class TestPromptStage(FlowTestCase):
placeholder="EMAIL_PLACEHOLDER", placeholder="EMAIL_PLACEHOLDER",
) )
password_prompt = Prompt.objects.create( password_prompt = Prompt.objects.create(
name=generate_id(),
field_key="password_prompt", field_key="password_prompt",
label="PASSWORD_LABEL", label="PASSWORD_LABEL",
type=FieldTypes.PASSWORD, type=FieldTypes.PASSWORD,
@ -58,6 +62,7 @@ class TestPromptStage(FlowTestCase):
placeholder="PASSWORD_PLACEHOLDER", placeholder="PASSWORD_PLACEHOLDER",
) )
password2_prompt = Prompt.objects.create( password2_prompt = Prompt.objects.create(
name=generate_id(),
field_key="password2_prompt", field_key="password2_prompt",
label="PASSWORD_LABEL", label="PASSWORD_LABEL",
type=FieldTypes.PASSWORD, type=FieldTypes.PASSWORD,
@ -65,6 +70,7 @@ class TestPromptStage(FlowTestCase):
placeholder="PASSWORD_PLACEHOLDER", placeholder="PASSWORD_PLACEHOLDER",
) )
number_prompt = Prompt.objects.create( number_prompt = Prompt.objects.create(
name=generate_id(),
field_key="number_prompt", field_key="number_prompt",
label="NUMBER_LABEL", label="NUMBER_LABEL",
type=FieldTypes.NUMBER, type=FieldTypes.NUMBER,
@ -72,12 +78,14 @@ class TestPromptStage(FlowTestCase):
placeholder="NUMBER_PLACEHOLDER", placeholder="NUMBER_PLACEHOLDER",
) )
hidden_prompt = Prompt.objects.create( hidden_prompt = Prompt.objects.create(
name=generate_id(),
field_key="hidden_prompt", field_key="hidden_prompt",
type=FieldTypes.HIDDEN, type=FieldTypes.HIDDEN,
required=True, required=True,
placeholder="HIDDEN_PLACEHOLDER", placeholder="HIDDEN_PLACEHOLDER",
) )
static_prompt = Prompt.objects.create( static_prompt = Prompt.objects.create(
name=generate_id(),
field_key="static_prompt", field_key="static_prompt",
type=FieldTypes.STATIC, type=FieldTypes.STATIC,
required=True, required=True,

View File

@ -17,9 +17,10 @@ entries:
placeholder_expression: false placeholder_expression: false
required: true required: true
type: text type: text
identifiers:
field_key: username field_key: username
label: Username label: Username
identifiers:
name: default-source-enrollment-field-username
id: prompt-field-username id: prompt-field-username
model: authentik_stages_prompt.prompt model: authentik_stages_prompt.prompt
- attrs: - attrs:

View File

@ -21,9 +21,10 @@ entries:
placeholder_expression: true placeholder_expression: true
required: true required: true
type: text type: text
identifiers:
field_key: username field_key: username
label: Username label: Username
identifiers:
name: default-user-settings-field-username
id: prompt-field-username id: prompt-field-username
model: authentik_stages_prompt.prompt model: authentik_stages_prompt.prompt
- attrs: - attrs:
@ -36,9 +37,10 @@ entries:
placeholder_expression: true placeholder_expression: true
required: true required: true
type: text type: text
identifiers:
field_key: name field_key: name
label: Name label: Name
identifiers:
name: default-user-settings-field-name
id: prompt-field-name id: prompt-field-name
model: authentik_stages_prompt.prompt model: authentik_stages_prompt.prompt
- attrs: - attrs:
@ -51,9 +53,10 @@ entries:
placeholder_expression: true placeholder_expression: true
required: true required: true
type: email type: email
identifiers:
field_key: email field_key: email
label: Email label: Email
identifiers:
name: default-user-settings-field-email
id: prompt-field-email id: prompt-field-email
model: authentik_stages_prompt.prompt model: authentik_stages_prompt.prompt
- attrs: - attrs:
@ -66,9 +69,10 @@ entries:
placeholder_expression: true placeholder_expression: true
required: true required: true
type: ak-locale type: ak-locale
identifiers:
field_key: attributes.settings.locale field_key: attributes.settings.locale
label: Locale label: Locale
identifiers:
name: default-user-settings-field-locale
id: prompt-field-locale id: prompt-field-locale
model: authentik_stages_prompt.prompt model: authentik_stages_prompt.prompt
- attrs: - attrs:

View File

@ -19,10 +19,11 @@ entries:
required: true required: true
sub_text: '' sub_text: ''
type: static type: static
id: prompt-field-header
identifiers:
field_key: oobe-header-text field_key: oobe-header-text
label: oobe-header-text label: oobe-header-text
id: prompt-field-header
identifiers:
name: initial-setup-field-header
model: authentik_stages_prompt.prompt model: authentik_stages_prompt.prompt
- attrs: - attrs:
order: 101 order: 101
@ -31,10 +32,11 @@ entries:
required: true required: true
sub_text: '' sub_text: ''
type: email type: email
field_key: email
label: Email
id: prompt-field-email id: prompt-field-email
identifiers: identifiers:
field_key: admin_email name: initial-setup-field-email
label: Email
model: authentik_stages_prompt.prompt model: authentik_stages_prompt.prompt
- attrs: - attrs:
order: 300 order: 300
@ -43,10 +45,11 @@ entries:
required: true required: true
sub_text: '' sub_text: ''
type: password type: password
id: prompt-field-password
identifiers:
field_key: password field_key: password
label: Password label: Password
id: prompt-field-password
identifiers:
name: initial-setup-field-password
model: authentik_stages_prompt.prompt model: authentik_stages_prompt.prompt
- attrs: - attrs:
order: 301 order: 301
@ -55,10 +58,11 @@ entries:
required: true required: true
sub_text: '' sub_text: ''
type: password type: password
id: prompt-field-password-repeat
identifiers:
field_key: password_repeat field_key: password_repeat
label: Password (repeat) label: Password (repeat)
id: prompt-field-password-repeat
identifiers:
name: initial-setup-field-password-repeat
model: authentik_stages_prompt.prompt model: authentik_stages_prompt.prompt
- attrs: - attrs:
expression: | expression: |
@ -66,8 +70,6 @@ entries:
# by injecting "pending_user" # by injecting "pending_user"
akadmin = ak_user_by(username="akadmin") akadmin = ak_user_by(username="akadmin")
context["flow_plan"].context["pending_user"] = akadmin context["flow_plan"].context["pending_user"] = akadmin
# Remap the email value
context["prompt_data"]["email"] = context["prompt_data"]["admin_email"]
return True return True
id: policy-default-oobe-prefill-user id: policy-default-oobe-prefill-user
identifiers: identifiers:

View File

@ -17,9 +17,10 @@ entries:
placeholder_expression: false placeholder_expression: false
required: true required: true
type: password type: password
identifiers:
field_key: password field_key: password
label: Password label: Password
identifiers:
name: default-password-change-field-password
id: prompt-field-password id: prompt-field-password
model: authentik_stages_prompt.prompt model: authentik_stages_prompt.prompt
- attrs: - attrs:
@ -28,9 +29,10 @@ entries:
placeholder_expression: false placeholder_expression: false
required: true required: true
type: password type: password
identifiers:
field_key: password_repeat field_key: password_repeat
label: Password (repeat) label: Password (repeat)
identifiers:
name: default-password-change-field-password-repeat
id: prompt-field-password-repeat id: prompt-field-password-repeat
model: authentik_stages_prompt.prompt model: authentik_stages_prompt.prompt
- attrs: - attrs:

View File

@ -13,56 +13,61 @@ entries:
title: Welcome to authentik! title: Welcome to authentik!
designation: enrollment designation: enrollment
authentication: require_unauthenticated authentication: require_unauthenticated
- identifiers: - id: prompt-field-username
model: authentik_stages_prompt.prompt
identifiers:
name: default-enrollment-field-username
attrs:
field_key: username field_key: username
label: Username label: Username
id: prompt-field-username
model: authentik_stages_prompt.prompt
attrs:
type: username type: username
required: true required: true
placeholder: Username placeholder: Username
placeholder_expression: false placeholder_expression: false
order: 0 order: 0
- identifiers: - identifiers:
field_key: password name: default-enrollment-field-password
label: Password
id: prompt-field-password id: prompt-field-password
model: authentik_stages_prompt.prompt model: authentik_stages_prompt.prompt
attrs: attrs:
field_key: password
label: Password
type: password type: password
required: true required: true
placeholder: Password placeholder: Password
placeholder_expression: false placeholder_expression: false
order: 0 order: 0
- identifiers: - identifiers:
field_key: password_repeat name: default-enrollment-field-password-repeat
label: Password (repeat)
id: prompt-field-password-repeat id: prompt-field-password-repeat
model: authentik_stages_prompt.prompt model: authentik_stages_prompt.prompt
attrs: attrs:
field_key: password_repeat
label: Password (repeat)
type: password type: password
required: true required: true
placeholder: Password (repeat) placeholder: Password (repeat)
placeholder_expression: false placeholder_expression: false
order: 1 order: 1
- identifiers: - identifiers:
field_key: name name: default-enrollment-field-name
label: Name
id: prompt-field-name id: prompt-field-name
model: authentik_stages_prompt.prompt model: authentik_stages_prompt.prompt
attrs: attrs:
field_key: name
label: Name
type: text type: text
required: true required: true
placeholder: Name placeholder: Name
placeholder_expression: false placeholder_expression: false
order: 0 order: 0
- identifiers: - identifiers:
field_key: email name: default-enrollment-field-email
label: Email
id: prompt-field-email id: prompt-field-email
model: authentik_stages_prompt.prompt model: authentik_stages_prompt.prompt
attrs: attrs:
field_key: email
label: Email
type: email type: email
required: true required: true
placeholder: Email placeholder: Email

View File

@ -14,55 +14,60 @@ entries:
designation: enrollment designation: enrollment
authentication: require_unauthenticated authentication: require_unauthenticated
- identifiers: - identifiers:
field_key: username name: default-enrollment-field-username
label: Username
id: prompt-field-username id: prompt-field-username
model: authentik_stages_prompt.prompt model: authentik_stages_prompt.prompt
attrs: attrs:
field_key: username
label: Username
type: username type: username
required: true required: true
placeholder: Username placeholder: Username
placeholder_expression: false placeholder_expression: false
order: 0 order: 0
- identifiers: - identifiers:
field_key: password name: default-enrollment-field-password
label: Password
id: prompt-field-password id: prompt-field-password
model: authentik_stages_prompt.prompt model: authentik_stages_prompt.prompt
attrs: attrs:
field_key: password
label: Password
type: password type: password
required: true required: true
placeholder: Password placeholder: Password
placeholder_expression: false placeholder_expression: false
order: 0 order: 0
- identifiers: - identifiers:
field_key: password_repeat name: default-enrollment-field-password-repeat
label: Password (repeat)
id: prompt-field-password-repeat id: prompt-field-password-repeat
model: authentik_stages_prompt.prompt model: authentik_stages_prompt.prompt
attrs: attrs:
field_key: password_repeat
label: Password (repeat)
type: password type: password
required: true required: true
placeholder: Password (repeat) placeholder: Password (repeat)
placeholder_expression: false placeholder_expression: false
order: 1 order: 1
- identifiers: - identifiers:
field_key: name name: default-enrollment-field-name
label: Name
id: prompt-field-name id: prompt-field-name
model: authentik_stages_prompt.prompt model: authentik_stages_prompt.prompt
attrs: attrs:
field_key: name
label: Name
type: text type: text
required: true required: true
placeholder: Name placeholder: Name
placeholder_expression: false placeholder_expression: false
order: 0 order: 0
- identifiers: - identifiers:
field_key: email name: default-enrollment-field-email
label: Email
id: prompt-field-email id: prompt-field-email
model: authentik_stages_prompt.prompt model: authentik_stages_prompt.prompt
attrs: attrs:
field_key: email
label: Email
type: email type: email
required: true required: true
placeholder: Email placeholder: Email

View File

@ -14,22 +14,24 @@ entries:
designation: recovery designation: recovery
authentication: require_unauthenticated authentication: require_unauthenticated
- identifiers: - identifiers:
field_key: password name: default-recovery-field-password
label: Password
id: prompt-field-password id: prompt-field-password
model: authentik_stages_prompt.prompt model: authentik_stages_prompt.prompt
attrs: attrs:
field_key: password
label: Password
type: password type: password
required: true required: true
placeholder: Password placeholder: Password
order: 0 order: 0
placeholder_expression: false placeholder_expression: false
- identifiers: - identifiers:
field_key: password_repeat name: default-recovery-field-password-repeat
label: Password (repeat)
id: prompt-field-password-repeat id: prompt-field-password-repeat
model: authentik_stages_prompt.prompt model: authentik_stages_prompt.prompt
attrs: attrs:
field_key: password_repeat
label: Password (repeat)
type: password type: password
required: true required: true
placeholder: Password (repeat) placeholder: Password (repeat)

View File

@ -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

View File

@ -23008,6 +23008,10 @@ paths:
name: label name: label
schema: schema:
type: string type: string
- in: query
name: name
schema:
type: string
- name: ordering - name: ordering
required: false required: false
in: query in: query
@ -34263,6 +34267,9 @@ components:
type: object type: object
description: Prompt Serializer description: Prompt Serializer
properties: properties:
name:
type: string
minLength: 1
field_key: field_key:
type: string type: string
minLength: 1 minLength: 1
@ -35278,6 +35285,8 @@ components:
format: uuid format: uuid
readOnly: true readOnly: true
title: Prompt uuid title: Prompt uuid
name:
type: string
field_key: field_key:
type: string type: string
description: Name of the form field, also used to store the value description: Name of the form field, also used to store the value
@ -35304,6 +35313,7 @@ components:
required: required:
- field_key - field_key
- label - label
- name
- pk - pk
- type - type
PromptChallenge: PromptChallenge:
@ -35345,6 +35355,9 @@ components:
type: object type: object
description: Prompt Serializer description: Prompt Serializer
properties: properties:
name:
type: string
minLength: 1
field_key: field_key:
type: string type: string
minLength: 1 minLength: 1
@ -35373,6 +35386,7 @@ components:
required: required:
- field_key - field_key
- label - label
- name
- type - type
PromptStage: PromptStage:
type: object type: object

View File

@ -26,8 +26,8 @@ class TestFlowsAuthenticator(SeleniumTestCase):
@retry() @retry()
@apply_blueprint( @apply_blueprint(
"default/10-flow-default-authentication-flow.yaml", "default/flow-default-authentication-flow.yaml",
"default/10-flow-default-invalidation-flow.yaml", "default/flow-default-invalidation-flow.yaml",
) )
def test_totp_validate(self): def test_totp_validate(self):
"""test flow with otp stages""" """test flow with otp stages"""
@ -52,10 +52,10 @@ class TestFlowsAuthenticator(SeleniumTestCase):
@retry() @retry()
@apply_blueprint( @apply_blueprint(
"default/10-flow-default-authentication-flow.yaml", "default/flow-default-authentication-flow.yaml",
"default/10-flow-default-invalidation-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): def test_totp_setup(self):
"""test TOTP Setup stage""" """test TOTP Setup stage"""
flow: Flow = Flow.objects.get(slug="default-authentication-flow") flow: Flow = Flow.objects.get(slug="default-authentication-flow")
@ -98,10 +98,10 @@ class TestFlowsAuthenticator(SeleniumTestCase):
@retry() @retry()
@apply_blueprint( @apply_blueprint(
"default/10-flow-default-authentication-flow.yaml", "default/flow-default-authentication-flow.yaml",
"default/10-flow-default-invalidation-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): def test_static_setup(self):
"""test Static OTP Setup stage""" """test Static OTP Setup stage"""
flow: Flow = Flow.objects.get(slug="default-authentication-flow") flow: Flow = Flow.objects.get(slug="default-authentication-flow")

View File

@ -41,19 +41,28 @@ class TestFlowsEnroll(SeleniumTestCase):
@retry() @retry()
@apply_blueprint( @apply_blueprint(
"default/10-flow-default-authentication-flow.yaml", "default/flow-default-authentication-flow.yaml",
"default/10-flow-default-invalidation-flow.yaml", "default/flow-default-invalidation-flow.yaml",
) )
def test_enroll_2_step(self): def test_enroll_2_step(self):
"""Test 2-step enroll flow""" """Test 2-step enroll flow"""
# First stage fields # First stage fields
username_prompt = Prompt.objects.create( 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( 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( password_repeat = Prompt.objects.create(
name=generate_id(),
field_key="password_repeat", field_key="password_repeat",
label="Password (repeat)", label="Password (repeat)",
order=2, order=2,
@ -62,10 +71,10 @@ class TestFlowsEnroll(SeleniumTestCase):
# Second stage fields # Second stage fields
name_field = Prompt.objects.create( 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( 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 # Stages
@ -107,19 +116,28 @@ class TestFlowsEnroll(SeleniumTestCase):
@retry() @retry()
@apply_blueprint( @apply_blueprint(
"default/10-flow-default-authentication-flow.yaml", "default/flow-default-authentication-flow.yaml",
"default/10-flow-default-invalidation-flow.yaml", "default/flow-default-invalidation-flow.yaml",
) )
def test_enroll_email(self): def test_enroll_email(self):
"""Test enroll with Email verification""" """Test enroll with Email verification"""
# First stage fields # First stage fields
username_prompt = Prompt.objects.create( 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( 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( password_repeat = Prompt.objects.create(
name=generate_id(),
field_key="password_repeat", field_key="password_repeat",
label="Password (repeat)", label="Password (repeat)",
order=2, order=2,
@ -128,10 +146,10 @@ class TestFlowsEnroll(SeleniumTestCase):
# Second stage fields # Second stage fields
name_field = Prompt.objects.create( 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( 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 # Stages

View File

@ -12,8 +12,8 @@ class TestFlowsLogin(SeleniumTestCase):
@retry() @retry()
@apply_blueprint( @apply_blueprint(
"default/10-flow-default-authentication-flow.yaml", "default/flow-default-authentication-flow.yaml",
"default/10-flow-default-invalidation-flow.yaml", "default/flow-default-invalidation-flow.yaml",
) )
def test_login(self): def test_login(self):
"""test default login flow""" """test default login flow"""

View File

@ -18,10 +18,10 @@ class TestFlowsStageSetup(SeleniumTestCase):
"""test stage setup flows""" """test stage setup flows"""
@retry() @retry()
@apply_blueprint("default/0-flow-password-change.yaml") @apply_blueprint("default/flow-password-change.yaml")
@apply_blueprint( @apply_blueprint(
"default/10-flow-default-authentication-flow.yaml", "default/flow-default-authentication-flow.yaml",
"default/10-flow-default-invalidation-flow.yaml", "default/flow-default-invalidation-flow.yaml",
) )
def test_password_change(self): def test_password_change(self):
"""test password change flow""" """test password change flow"""

View File

@ -81,8 +81,8 @@ class TestProviderLDAP(SeleniumTestCase):
@retry() @retry()
@apply_blueprint( @apply_blueprint(
"default/10-flow-default-authentication-flow.yaml", "default/flow-default-authentication-flow.yaml",
"default/10-flow-default-invalidation-flow.yaml", "default/flow-default-invalidation-flow.yaml",
) )
def test_ldap_bind_success(self): def test_ldap_bind_success(self):
"""Test simple bind""" """Test simple bind"""
@ -108,8 +108,8 @@ class TestProviderLDAP(SeleniumTestCase):
@retry() @retry()
@apply_blueprint( @apply_blueprint(
"default/10-flow-default-authentication-flow.yaml", "default/flow-default-authentication-flow.yaml",
"default/10-flow-default-invalidation-flow.yaml", "default/flow-default-invalidation-flow.yaml",
) )
def test_ldap_bind_success_ssl(self): def test_ldap_bind_success_ssl(self):
"""Test simple bind with ssl""" """Test simple bind with ssl"""
@ -135,8 +135,8 @@ class TestProviderLDAP(SeleniumTestCase):
@retry() @retry()
@apply_blueprint( @apply_blueprint(
"default/10-flow-default-authentication-flow.yaml", "default/flow-default-authentication-flow.yaml",
"default/10-flow-default-invalidation-flow.yaml", "default/flow-default-invalidation-flow.yaml",
) )
def test_ldap_bind_fail(self): def test_ldap_bind_fail(self):
"""Test simple bind (failed)""" """Test simple bind (failed)"""
@ -160,8 +160,8 @@ class TestProviderLDAP(SeleniumTestCase):
@retry() @retry()
@apply_blueprint( @apply_blueprint(
"default/10-flow-default-authentication-flow.yaml", "default/flow-default-authentication-flow.yaml",
"default/10-flow-default-invalidation-flow.yaml", "default/flow-default-invalidation-flow.yaml",
) )
@reconcile_app("authentik_outposts") @reconcile_app("authentik_outposts")
def test_ldap_bind_search(self): def test_ldap_bind_search(self):

View File

@ -58,12 +58,12 @@ class TestProviderOAuth2Github(SeleniumTestCase):
@retry() @retry()
@apply_blueprint( @apply_blueprint(
"default/10-flow-default-authentication-flow.yaml", "default/flow-default-authentication-flow.yaml",
"default/10-flow-default-invalidation-flow.yaml", "default/flow-default-invalidation-flow.yaml",
) )
@apply_blueprint( @apply_blueprint(
"default/20-flow-default-provider-authorization-explicit-consent.yaml", "default/flow-default-provider-authorization-explicit-consent.yaml",
"default/20-flow-default-provider-authorization-implicit-consent.yaml", "default/flow-default-provider-authorization-implicit-consent.yaml",
) )
@apply_blueprint( @apply_blueprint(
"system/providers-oauth2.yaml", "system/providers-oauth2.yaml",
@ -114,12 +114,12 @@ class TestProviderOAuth2Github(SeleniumTestCase):
@retry() @retry()
@apply_blueprint( @apply_blueprint(
"default/10-flow-default-authentication-flow.yaml", "default/flow-default-authentication-flow.yaml",
"default/10-flow-default-invalidation-flow.yaml", "default/flow-default-invalidation-flow.yaml",
) )
@apply_blueprint( @apply_blueprint(
"default/20-flow-default-provider-authorization-explicit-consent.yaml", "default/flow-default-provider-authorization-explicit-consent.yaml",
"default/20-flow-default-provider-authorization-implicit-consent.yaml", "default/flow-default-provider-authorization-implicit-consent.yaml",
) )
@apply_blueprint( @apply_blueprint(
"system/providers-oauth2.yaml", "system/providers-oauth2.yaml",
@ -189,12 +189,12 @@ class TestProviderOAuth2Github(SeleniumTestCase):
@retry() @retry()
@apply_blueprint( @apply_blueprint(
"default/10-flow-default-authentication-flow.yaml", "default/flow-default-authentication-flow.yaml",
"default/10-flow-default-invalidation-flow.yaml", "default/flow-default-invalidation-flow.yaml",
) )
@apply_blueprint( @apply_blueprint(
"default/20-flow-default-provider-authorization-explicit-consent.yaml", "default/flow-default-provider-authorization-explicit-consent.yaml",
"default/20-flow-default-provider-authorization-implicit-consent.yaml", "default/flow-default-provider-authorization-implicit-consent.yaml",
) )
@reconcile_app("authentik_crypto") @reconcile_app("authentik_crypto")
def test_denied(self): def test_denied(self):

View File

@ -67,12 +67,12 @@ class TestProviderOAuth2OAuth(SeleniumTestCase):
@retry() @retry()
@apply_blueprint( @apply_blueprint(
"default/10-flow-default-authentication-flow.yaml", "default/flow-default-authentication-flow.yaml",
"default/10-flow-default-invalidation-flow.yaml", "default/flow-default-invalidation-flow.yaml",
) )
@apply_blueprint( @apply_blueprint(
"default/20-flow-default-provider-authorization-explicit-consent.yaml", "default/flow-default-provider-authorization-explicit-consent.yaml",
"default/20-flow-default-provider-authorization-implicit-consent.yaml", "default/flow-default-provider-authorization-implicit-consent.yaml",
) )
@apply_blueprint( @apply_blueprint(
"system/providers-oauth2.yaml", "system/providers-oauth2.yaml",
@ -116,12 +116,12 @@ class TestProviderOAuth2OAuth(SeleniumTestCase):
@retry() @retry()
@apply_blueprint( @apply_blueprint(
"default/10-flow-default-authentication-flow.yaml", "default/flow-default-authentication-flow.yaml",
"default/10-flow-default-invalidation-flow.yaml", "default/flow-default-invalidation-flow.yaml",
) )
@apply_blueprint( @apply_blueprint(
"default/20-flow-default-provider-authorization-explicit-consent.yaml", "default/flow-default-provider-authorization-explicit-consent.yaml",
"default/20-flow-default-provider-authorization-implicit-consent.yaml", "default/flow-default-provider-authorization-implicit-consent.yaml",
) )
@apply_blueprint( @apply_blueprint(
"system/providers-oauth2.yaml", "system/providers-oauth2.yaml",
@ -178,12 +178,12 @@ class TestProviderOAuth2OAuth(SeleniumTestCase):
@retry() @retry()
@apply_blueprint( @apply_blueprint(
"default/10-flow-default-authentication-flow.yaml", "default/flow-default-authentication-flow.yaml",
"default/10-flow-default-invalidation-flow.yaml", "default/flow-default-invalidation-flow.yaml",
) )
@apply_blueprint( @apply_blueprint(
"default/20-flow-default-provider-authorization-explicit-consent.yaml", "default/flow-default-provider-authorization-explicit-consent.yaml",
"default/20-flow-default-provider-authorization-implicit-consent.yaml", "default/flow-default-provider-authorization-implicit-consent.yaml",
) )
@apply_blueprint( @apply_blueprint(
"system/providers-oauth2.yaml", "system/providers-oauth2.yaml",
@ -249,12 +249,12 @@ class TestProviderOAuth2OAuth(SeleniumTestCase):
@retry() @retry()
@apply_blueprint( @apply_blueprint(
"default/10-flow-default-authentication-flow.yaml", "default/flow-default-authentication-flow.yaml",
"default/10-flow-default-invalidation-flow.yaml", "default/flow-default-invalidation-flow.yaml",
) )
@apply_blueprint( @apply_blueprint(
"default/20-flow-default-provider-authorization-explicit-consent.yaml", "default/flow-default-provider-authorization-explicit-consent.yaml",
"default/20-flow-default-provider-authorization-implicit-consent.yaml", "default/flow-default-provider-authorization-implicit-consent.yaml",
) )
@apply_blueprint( @apply_blueprint(
"system/providers-oauth2.yaml", "system/providers-oauth2.yaml",
@ -329,12 +329,12 @@ class TestProviderOAuth2OAuth(SeleniumTestCase):
@retry() @retry()
@apply_blueprint( @apply_blueprint(
"default/10-flow-default-authentication-flow.yaml", "default/flow-default-authentication-flow.yaml",
"default/10-flow-default-invalidation-flow.yaml", "default/flow-default-invalidation-flow.yaml",
) )
@apply_blueprint( @apply_blueprint(
"default/20-flow-default-provider-authorization-explicit-consent.yaml", "default/flow-default-provider-authorization-explicit-consent.yaml",
"default/20-flow-default-provider-authorization-implicit-consent.yaml", "default/flow-default-provider-authorization-implicit-consent.yaml",
) )
@apply_blueprint( @apply_blueprint(
"system/providers-oauth2.yaml", "system/providers-oauth2.yaml",

View File

@ -65,12 +65,12 @@ class TestProviderOAuth2OIDC(SeleniumTestCase):
@retry() @retry()
@apply_blueprint( @apply_blueprint(
"default/10-flow-default-authentication-flow.yaml", "default/flow-default-authentication-flow.yaml",
"default/10-flow-default-invalidation-flow.yaml", "default/flow-default-invalidation-flow.yaml",
) )
@apply_blueprint( @apply_blueprint(
"default/20-flow-default-provider-authorization-explicit-consent.yaml", "default/flow-default-provider-authorization-explicit-consent.yaml",
"default/20-flow-default-provider-authorization-implicit-consent.yaml", "default/flow-default-provider-authorization-implicit-consent.yaml",
) )
@reconcile_app("authentik_crypto") @reconcile_app("authentik_crypto")
def test_redirect_uri_error(self): def test_redirect_uri_error(self):
@ -111,12 +111,12 @@ class TestProviderOAuth2OIDC(SeleniumTestCase):
@retry() @retry()
@apply_blueprint( @apply_blueprint(
"default/10-flow-default-authentication-flow.yaml", "default/flow-default-authentication-flow.yaml",
"default/10-flow-default-invalidation-flow.yaml", "default/flow-default-invalidation-flow.yaml",
) )
@apply_blueprint( @apply_blueprint(
"default/20-flow-default-provider-authorization-explicit-consent.yaml", "default/flow-default-provider-authorization-explicit-consent.yaml",
"default/20-flow-default-provider-authorization-implicit-consent.yaml", "default/flow-default-provider-authorization-implicit-consent.yaml",
) )
@reconcile_app("authentik_crypto") @reconcile_app("authentik_crypto")
@apply_blueprint("system/providers-oauth2.yaml") @apply_blueprint("system/providers-oauth2.yaml")
@ -166,12 +166,12 @@ class TestProviderOAuth2OIDC(SeleniumTestCase):
@retry() @retry()
@apply_blueprint( @apply_blueprint(
"default/10-flow-default-authentication-flow.yaml", "default/flow-default-authentication-flow.yaml",
"default/10-flow-default-invalidation-flow.yaml", "default/flow-default-invalidation-flow.yaml",
) )
@apply_blueprint( @apply_blueprint(
"default/20-flow-default-provider-authorization-explicit-consent.yaml", "default/flow-default-provider-authorization-explicit-consent.yaml",
"default/20-flow-default-provider-authorization-implicit-consent.yaml", "default/flow-default-provider-authorization-implicit-consent.yaml",
) )
@reconcile_app("authentik_crypto") @reconcile_app("authentik_crypto")
@apply_blueprint("system/providers-oauth2.yaml") @apply_blueprint("system/providers-oauth2.yaml")
@ -236,12 +236,12 @@ class TestProviderOAuth2OIDC(SeleniumTestCase):
@retry() @retry()
@apply_blueprint( @apply_blueprint(
"default/10-flow-default-authentication-flow.yaml", "default/flow-default-authentication-flow.yaml",
"default/10-flow-default-invalidation-flow.yaml", "default/flow-default-invalidation-flow.yaml",
) )
@apply_blueprint( @apply_blueprint(
"default/20-flow-default-provider-authorization-explicit-consent.yaml", "default/flow-default-provider-authorization-explicit-consent.yaml",
"default/20-flow-default-provider-authorization-implicit-consent.yaml", "default/flow-default-provider-authorization-implicit-consent.yaml",
) )
@reconcile_app("authentik_crypto") @reconcile_app("authentik_crypto")
def test_authorization_denied(self): def test_authorization_denied(self):

View File

@ -65,12 +65,12 @@ class TestProviderOAuth2OIDCImplicit(SeleniumTestCase):
@retry() @retry()
@apply_blueprint( @apply_blueprint(
"default/10-flow-default-authentication-flow.yaml", "default/flow-default-authentication-flow.yaml",
"default/10-flow-default-invalidation-flow.yaml", "default/flow-default-invalidation-flow.yaml",
) )
@apply_blueprint( @apply_blueprint(
"default/20-flow-default-provider-authorization-explicit-consent.yaml", "default/flow-default-provider-authorization-explicit-consent.yaml",
"default/20-flow-default-provider-authorization-implicit-consent.yaml", "default/flow-default-provider-authorization-implicit-consent.yaml",
) )
@reconcile_app("authentik_crypto") @reconcile_app("authentik_crypto")
def test_redirect_uri_error(self): def test_redirect_uri_error(self):
@ -111,12 +111,12 @@ class TestProviderOAuth2OIDCImplicit(SeleniumTestCase):
@retry() @retry()
@apply_blueprint( @apply_blueprint(
"default/10-flow-default-authentication-flow.yaml", "default/flow-default-authentication-flow.yaml",
"default/10-flow-default-invalidation-flow.yaml", "default/flow-default-invalidation-flow.yaml",
) )
@apply_blueprint( @apply_blueprint(
"default/20-flow-default-provider-authorization-explicit-consent.yaml", "default/flow-default-provider-authorization-explicit-consent.yaml",
"default/20-flow-default-provider-authorization-implicit-consent.yaml", "default/flow-default-provider-authorization-implicit-consent.yaml",
) )
@reconcile_app("authentik_crypto") @reconcile_app("authentik_crypto")
@apply_blueprint("system/providers-oauth2.yaml") @apply_blueprint("system/providers-oauth2.yaml")
@ -161,12 +161,12 @@ class TestProviderOAuth2OIDCImplicit(SeleniumTestCase):
@retry() @retry()
@apply_blueprint( @apply_blueprint(
"default/10-flow-default-authentication-flow.yaml", "default/flow-default-authentication-flow.yaml",
"default/10-flow-default-invalidation-flow.yaml", "default/flow-default-invalidation-flow.yaml",
) )
@apply_blueprint( @apply_blueprint(
"default/20-flow-default-provider-authorization-explicit-consent.yaml", "default/flow-default-provider-authorization-explicit-consent.yaml",
"default/20-flow-default-provider-authorization-implicit-consent.yaml", "default/flow-default-provider-authorization-implicit-consent.yaml",
) )
@reconcile_app("authentik_crypto") @reconcile_app("authentik_crypto")
@apply_blueprint("system/providers-oauth2.yaml") @apply_blueprint("system/providers-oauth2.yaml")
@ -227,12 +227,12 @@ class TestProviderOAuth2OIDCImplicit(SeleniumTestCase):
@retry() @retry()
@apply_blueprint( @apply_blueprint(
"default/10-flow-default-authentication-flow.yaml", "default/flow-default-authentication-flow.yaml",
"default/10-flow-default-invalidation-flow.yaml", "default/flow-default-invalidation-flow.yaml",
) )
@apply_blueprint( @apply_blueprint(
"default/20-flow-default-provider-authorization-explicit-consent.yaml", "default/flow-default-provider-authorization-explicit-consent.yaml",
"default/20-flow-default-provider-authorization-implicit-consent.yaml", "default/flow-default-provider-authorization-implicit-consent.yaml",
) )
@reconcile_app("authentik_crypto") @reconcile_app("authentik_crypto")
def test_authorization_denied(self): def test_authorization_denied(self):

View File

@ -57,12 +57,12 @@ class TestProviderProxy(SeleniumTestCase):
@retry() @retry()
@apply_blueprint( @apply_blueprint(
"default/10-flow-default-authentication-flow.yaml", "default/flow-default-authentication-flow.yaml",
"default/10-flow-default-invalidation-flow.yaml", "default/flow-default-invalidation-flow.yaml",
) )
@apply_blueprint( @apply_blueprint(
"default/20-flow-default-provider-authorization-explicit-consent.yaml", "default/flow-default-provider-authorization-explicit-consent.yaml",
"default/20-flow-default-provider-authorization-implicit-consent.yaml", "default/flow-default-provider-authorization-implicit-consent.yaml",
) )
@apply_blueprint( @apply_blueprint(
"system/providers-oauth2.yaml", "system/providers-oauth2.yaml",
@ -123,12 +123,12 @@ class TestProviderProxy(SeleniumTestCase):
@retry() @retry()
@apply_blueprint( @apply_blueprint(
"default/10-flow-default-authentication-flow.yaml", "default/flow-default-authentication-flow.yaml",
"default/10-flow-default-invalidation-flow.yaml", "default/flow-default-invalidation-flow.yaml",
) )
@apply_blueprint( @apply_blueprint(
"default/20-flow-default-provider-authorization-explicit-consent.yaml", "default/flow-default-provider-authorization-explicit-consent.yaml",
"default/20-flow-default-provider-authorization-implicit-consent.yaml", "default/flow-default-provider-authorization-implicit-consent.yaml",
) )
@apply_blueprint( @apply_blueprint(
"system/providers-oauth2.yaml", "system/providers-oauth2.yaml",
@ -200,12 +200,12 @@ class TestProviderProxyConnect(ChannelsLiveServerTestCase):
@retry() @retry()
@apply_blueprint( @apply_blueprint(
"default/10-flow-default-authentication-flow.yaml", "default/flow-default-authentication-flow.yaml",
"default/10-flow-default-invalidation-flow.yaml", "default/flow-default-invalidation-flow.yaml",
) )
@apply_blueprint( @apply_blueprint(
"default/20-flow-default-provider-authorization-explicit-consent.yaml", "default/flow-default-provider-authorization-explicit-consent.yaml",
"default/20-flow-default-provider-authorization-implicit-consent.yaml", "default/flow-default-provider-authorization-implicit-consent.yaml",
) )
@reconcile_app("authentik_crypto") @reconcile_app("authentik_crypto")
def test_proxy_connectivity(self): def test_proxy_connectivity(self):

View File

@ -64,12 +64,12 @@ class TestProviderSAML(SeleniumTestCase):
@retry() @retry()
@apply_blueprint( @apply_blueprint(
"default/10-flow-default-authentication-flow.yaml", "default/flow-default-authentication-flow.yaml",
"default/10-flow-default-invalidation-flow.yaml", "default/flow-default-invalidation-flow.yaml",
) )
@apply_blueprint( @apply_blueprint(
"default/20-flow-default-provider-authorization-explicit-consent.yaml", "default/flow-default-provider-authorization-explicit-consent.yaml",
"default/20-flow-default-provider-authorization-implicit-consent.yaml", "default/flow-default-provider-authorization-implicit-consent.yaml",
) )
@apply_blueprint( @apply_blueprint(
"system/providers-saml.yaml", "system/providers-saml.yaml",
@ -133,12 +133,12 @@ class TestProviderSAML(SeleniumTestCase):
@retry() @retry()
@apply_blueprint( @apply_blueprint(
"default/10-flow-default-authentication-flow.yaml", "default/flow-default-authentication-flow.yaml",
"default/10-flow-default-invalidation-flow.yaml", "default/flow-default-invalidation-flow.yaml",
) )
@apply_blueprint( @apply_blueprint(
"default/20-flow-default-provider-authorization-explicit-consent.yaml", "default/flow-default-provider-authorization-explicit-consent.yaml",
"default/20-flow-default-provider-authorization-implicit-consent.yaml", "default/flow-default-provider-authorization-implicit-consent.yaml",
) )
@apply_blueprint( @apply_blueprint(
"system/providers-saml.yaml", "system/providers-saml.yaml",
@ -217,12 +217,12 @@ class TestProviderSAML(SeleniumTestCase):
@retry() @retry()
@apply_blueprint( @apply_blueprint(
"default/10-flow-default-authentication-flow.yaml", "default/flow-default-authentication-flow.yaml",
"default/10-flow-default-invalidation-flow.yaml", "default/flow-default-invalidation-flow.yaml",
) )
@apply_blueprint( @apply_blueprint(
"default/20-flow-default-provider-authorization-explicit-consent.yaml", "default/flow-default-provider-authorization-explicit-consent.yaml",
"default/20-flow-default-provider-authorization-implicit-consent.yaml", "default/flow-default-provider-authorization-implicit-consent.yaml",
) )
@apply_blueprint( @apply_blueprint(
"system/providers-saml.yaml", "system/providers-saml.yaml",
@ -301,12 +301,12 @@ class TestProviderSAML(SeleniumTestCase):
@retry() @retry()
@apply_blueprint( @apply_blueprint(
"default/10-flow-default-authentication-flow.yaml", "default/flow-default-authentication-flow.yaml",
"default/10-flow-default-invalidation-flow.yaml", "default/flow-default-invalidation-flow.yaml",
) )
@apply_blueprint( @apply_blueprint(
"default/20-flow-default-provider-authorization-explicit-consent.yaml", "default/flow-default-provider-authorization-explicit-consent.yaml",
"default/20-flow-default-provider-authorization-implicit-consent.yaml", "default/flow-default-provider-authorization-implicit-consent.yaml",
) )
@apply_blueprint( @apply_blueprint(
"system/providers-saml.yaml", "system/providers-saml.yaml",
@ -376,12 +376,12 @@ class TestProviderSAML(SeleniumTestCase):
@retry() @retry()
@apply_blueprint( @apply_blueprint(
"default/10-flow-default-authentication-flow.yaml", "default/flow-default-authentication-flow.yaml",
"default/10-flow-default-invalidation-flow.yaml", "default/flow-default-invalidation-flow.yaml",
) )
@apply_blueprint( @apply_blueprint(
"default/20-flow-default-provider-authorization-explicit-consent.yaml", "default/flow-default-provider-authorization-explicit-consent.yaml",
"default/20-flow-default-provider-authorization-implicit-consent.yaml", "default/flow-default-provider-authorization-implicit-consent.yaml",
) )
@apply_blueprint( @apply_blueprint(
"system/providers-saml.yaml", "system/providers-saml.yaml",
@ -425,12 +425,12 @@ class TestProviderSAML(SeleniumTestCase):
@retry() @retry()
@apply_blueprint( @apply_blueprint(
"default/10-flow-default-authentication-flow.yaml", "default/flow-default-authentication-flow.yaml",
"default/10-flow-default-invalidation-flow.yaml", "default/flow-default-invalidation-flow.yaml",
) )
@apply_blueprint( @apply_blueprint(
"default/20-flow-default-provider-authorization-explicit-consent.yaml", "default/flow-default-provider-authorization-explicit-consent.yaml",
"default/20-flow-default-provider-authorization-implicit-consent.yaml", "default/flow-default-provider-authorization-implicit-consent.yaml",
) )
@apply_blueprint( @apply_blueprint(
"system/providers-saml.yaml", "system/providers-saml.yaml",

View File

@ -143,17 +143,17 @@ class TestSourceOAuth2(SeleniumTestCase):
@retry() @retry()
@apply_blueprint( @apply_blueprint(
"default/10-flow-default-authentication-flow.yaml", "default/flow-default-authentication-flow.yaml",
"default/10-flow-default-invalidation-flow.yaml", "default/flow-default-invalidation-flow.yaml",
) )
@apply_blueprint( @apply_blueprint(
"default/20-flow-default-provider-authorization-explicit-consent.yaml", "default/flow-default-provider-authorization-explicit-consent.yaml",
"default/20-flow-default-provider-authorization-implicit-consent.yaml", "default/flow-default-provider-authorization-implicit-consent.yaml",
) )
@apply_blueprint( @apply_blueprint(
"default/20-flow-default-source-authentication.yaml", "default/flow-default-source-authentication.yaml",
"default/20-flow-default-source-enrollment.yaml", "default/flow-default-source-enrollment.yaml",
"default/20-flow-default-source-pre-authentication.yaml", "default/flow-default-source-pre-authentication.yaml",
) )
def test_oauth_enroll(self): def test_oauth_enroll(self):
"""test OAuth Source With With OIDC""" """test OAuth Source With With OIDC"""
@ -200,12 +200,12 @@ class TestSourceOAuth2(SeleniumTestCase):
@retry() @retry()
@apply_blueprint( @apply_blueprint(
"default/10-flow-default-authentication-flow.yaml", "default/flow-default-authentication-flow.yaml",
"default/10-flow-default-invalidation-flow.yaml", "default/flow-default-invalidation-flow.yaml",
) )
@apply_blueprint( @apply_blueprint(
"default/20-flow-default-provider-authorization-explicit-consent.yaml", "default/flow-default-provider-authorization-explicit-consent.yaml",
"default/20-flow-default-provider-authorization-implicit-consent.yaml", "default/flow-default-provider-authorization-implicit-consent.yaml",
) )
def test_oauth_enroll_auth(self): def test_oauth_enroll_auth(self):
"""test OAuth Source With With OIDC (enroll and authenticate again)""" """test OAuth Source With With OIDC (enroll and authenticate again)"""
@ -292,13 +292,13 @@ class TestSourceOAuth1(SeleniumTestCase):
@retry() @retry()
@apply_blueprint( @apply_blueprint(
"default/10-flow-default-authentication-flow.yaml", "default/flow-default-authentication-flow.yaml",
"default/10-flow-default-invalidation-flow.yaml", "default/flow-default-invalidation-flow.yaml",
) )
@apply_blueprint( @apply_blueprint(
"default/20-flow-default-source-authentication.yaml", "default/flow-default-source-authentication.yaml",
"default/20-flow-default-source-enrollment.yaml", "default/flow-default-source-enrollment.yaml",
"default/20-flow-default-source-pre-authentication.yaml", "default/flow-default-source-pre-authentication.yaml",
) )
def test_oauth_enroll(self): def test_oauth_enroll(self):
"""test OAuth Source With With OIDC""" """test OAuth Source With With OIDC"""

View File

@ -96,13 +96,13 @@ class TestSourceSAML(SeleniumTestCase):
@retry() @retry()
@apply_blueprint( @apply_blueprint(
"default/10-flow-default-authentication-flow.yaml", "default/flow-default-authentication-flow.yaml",
"default/10-flow-default-invalidation-flow.yaml", "default/flow-default-invalidation-flow.yaml",
) )
@apply_blueprint( @apply_blueprint(
"default/20-flow-default-source-authentication.yaml", "default/flow-default-source-authentication.yaml",
"default/20-flow-default-source-enrollment.yaml", "default/flow-default-source-enrollment.yaml",
"default/20-flow-default-source-pre-authentication.yaml", "default/flow-default-source-pre-authentication.yaml",
) )
def test_idp_redirect(self): def test_idp_redirect(self):
"""test SAML Source With redirect binding""" """test SAML Source With redirect binding"""
@ -166,13 +166,13 @@ class TestSourceSAML(SeleniumTestCase):
@retry() @retry()
@apply_blueprint( @apply_blueprint(
"default/10-flow-default-authentication-flow.yaml", "default/flow-default-authentication-flow.yaml",
"default/10-flow-default-invalidation-flow.yaml", "default/flow-default-invalidation-flow.yaml",
) )
@apply_blueprint( @apply_blueprint(
"default/20-flow-default-source-authentication.yaml", "default/flow-default-source-authentication.yaml",
"default/20-flow-default-source-enrollment.yaml", "default/flow-default-source-enrollment.yaml",
"default/20-flow-default-source-pre-authentication.yaml", "default/flow-default-source-pre-authentication.yaml",
) )
def test_idp_post(self): def test_idp_post(self):
"""test SAML Source With post binding""" """test SAML Source With post binding"""
@ -249,13 +249,13 @@ class TestSourceSAML(SeleniumTestCase):
@retry() @retry()
@apply_blueprint( @apply_blueprint(
"default/10-flow-default-authentication-flow.yaml", "default/flow-default-authentication-flow.yaml",
"default/10-flow-default-invalidation-flow.yaml", "default/flow-default-invalidation-flow.yaml",
) )
@apply_blueprint( @apply_blueprint(
"default/20-flow-default-source-authentication.yaml", "default/flow-default-source-authentication.yaml",
"default/20-flow-default-source-enrollment.yaml", "default/flow-default-source-enrollment.yaml",
"default/20-flow-default-source-pre-authentication.yaml", "default/flow-default-source-pre-authentication.yaml",
) )
def test_idp_post_auto(self): def test_idp_post_auto(self):
"""test SAML Source With post binding (auto redirect)""" """test SAML Source With post binding (auto redirect)"""

View File

@ -13,9 +13,11 @@ import { TablePage } from "@goauthentik/elements/table/TablePage";
import { t } from "@lingui/macro"; import { t } from "@lingui/macro";
import { TemplateResult, html } from "lit"; import { CSSResult, TemplateResult, html } from "lit";
import { customElement, property } from "lit/decorators.js"; import { customElement, property } from "lit/decorators.js";
import PFDescriptionList from "@patternfly/patternfly/components/DescriptionList/description-list.css";
import { BlueprintInstance, BlueprintInstanceStatusEnum, ManagedApi } from "@goauthentik/api"; import { BlueprintInstance, BlueprintInstanceStatusEnum, ManagedApi } from "@goauthentik/api";
export function BlueprintStatus(blueprint?: BlueprintInstance): string { export function BlueprintStatus(blueprint?: BlueprintInstance): string {
@ -32,6 +34,7 @@ export function BlueprintStatus(blueprint?: BlueprintInstance): string {
} }
return t`Unknown`; return t`Unknown`;
} }
@customElement("ak-blueprint-list") @customElement("ak-blueprint-list")
export class BlueprintListPage extends TablePage<BlueprintInstance> { export class BlueprintListPage extends TablePage<BlueprintInstance> {
searchEnabled(): boolean { searchEnabled(): boolean {
@ -47,11 +50,16 @@ export class BlueprintListPage extends TablePage<BlueprintInstance> {
return "pf-icon pf-icon-blueprint"; return "pf-icon pf-icon-blueprint";
} }
expandable = true;
checkbox = true; checkbox = true;
@property() @property()
order = "name"; order = "name";
static get styles(): CSSResult[] {
return super.styles.concat(PFDescriptionList);
}
async apiEndpoint(page: number): Promise<PaginatedResponse<BlueprintInstance>> { async apiEndpoint(page: number): Promise<PaginatedResponse<BlueprintInstance>> {
return new ManagedApi(DEFAULT_CONFIG).managedBlueprintsList({ return new ManagedApi(DEFAULT_CONFIG).managedBlueprintsList({
ordering: this.order, ordering: this.order,
@ -96,9 +104,34 @@ export class BlueprintListPage extends TablePage<BlueprintInstance> {
</ak-forms-delete-bulk>`; </ak-forms-delete-bulk>`;
} }
renderExpanded(item: BlueprintInstance): TemplateResult {
return html`<td role="cell" colspan="4">
<div class="pf-c-table__expandable-row-content">
<dl class="pf-c-description-list pf-m-horizontal">
<div class="pf-c-description-list__group">
<dt class="pf-c-description-list__term">
<span class="pf-c-description-list__text">${t`Path`}</span>
</dt>
<dd class="pf-c-description-list__description">
<div class="pf-c-description-list__text">
<pre>${item.path}</pre>
</div>
</dd>
</div>
</dl>
</div>
</td>`;
}
row(item: BlueprintInstance): TemplateResult[] { 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 [ return [
html`${item.name}`, html`<div>${item.name}</div>
${description ? html`<small>${description}</small>` : html``}`,
html`${BlueprintStatus(item)}`, html`${BlueprintStatus(item)}`,
html`${item.lastApplied.toLocaleString()}`, html`${item.lastApplied.toLocaleString()}`,
html`<ak-label color=${item.enabled ? PFColor.Green : PFColor.Red}> html`<ak-label color=${item.enabled ? PFColor.Green : PFColor.Red}>

View File

@ -132,6 +132,17 @@ export class PromptForm extends ModelForm<Prompt, string> {
renderForm(): TemplateResult { renderForm(): TemplateResult {
return html`<form class="pf-c-form pf-m-horizontal"> return html`<form class="pf-c-form pf-m-horizontal">
<ak-form-element-horizontal label=${t`Name`} ?required=${true} name="name">
<input
type="text"
value="${ifDefined(this.instance?.name)}"
class="pf-c-form-control"
required
/>
<p class="pf-c-form__helper-text">
${t`Unique name of this field, used for selecting fields in prompt stages.`}
</p>
</ak-form-element-horizontal>
<ak-form-element-horizontal label=${t`Field Key`} ?required=${true} name="fieldKey"> <ak-form-element-horizontal label=${t`Field Key`} ?required=${true} name="fieldKey">
<input <input
type="text" type="text"

View File

@ -1,7 +1,6 @@
import "@goauthentik/admin/stages/prompt/PromptForm"; import "@goauthentik/admin/stages/prompt/PromptForm";
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import { uiConfig } from "@goauthentik/common/ui/config"; import { uiConfig } from "@goauthentik/common/ui/config";
import { truncate } from "@goauthentik/common/utils";
import "@goauthentik/elements/buttons/ModalButton"; import "@goauthentik/elements/buttons/ModalButton";
import "@goauthentik/elements/buttons/SpinnerButton"; import "@goauthentik/elements/buttons/SpinnerButton";
import "@goauthentik/elements/forms/DeleteBulkForm"; import "@goauthentik/elements/forms/DeleteBulkForm";
@ -35,7 +34,7 @@ export class PromptListPage extends TablePage<Prompt> {
checkbox = true; checkbox = true;
@property() @property()
order = "order"; order = "name";
async apiEndpoint(page: number): Promise<PaginatedResponse<Prompt>> { async apiEndpoint(page: number): Promise<PaginatedResponse<Prompt>> {
return new StagesApi(DEFAULT_CONFIG).stagesPromptPromptsList({ return new StagesApi(DEFAULT_CONFIG).stagesPromptPromptsList({
@ -48,8 +47,8 @@ export class PromptListPage extends TablePage<Prompt> {
columns(): TableColumn[] { columns(): TableColumn[] {
return [ return [
new TableColumn(t`Name`, "name"),
new TableColumn(t`Field`, "field_key"), new TableColumn(t`Field`, "field_key"),
new TableColumn(t`Label`, "label"),
new TableColumn(t`Type`, "type"), new TableColumn(t`Type`, "type"),
new TableColumn(t`Order`, "order"), new TableColumn(t`Order`, "order"),
new TableColumn(t`Stages`), new TableColumn(t`Stages`),
@ -81,8 +80,8 @@ export class PromptListPage extends TablePage<Prompt> {
row(item: Prompt): TemplateResult[] { row(item: Prompt): TemplateResult[] {
return [ return [
html`${item.fieldKey}`, html`${item.name}`,
html`${truncate(item.label, 20)}`, html`<code>${item.fieldKey}</code>`,
html`${item.type}`, html`${item.type}`,
html`${item.order}`, html`${item.order}`,
html`${item.promptstageSet?.map((stage) => { html`${item.promptstageSet?.map((stage) => {

View File

@ -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. 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 ## 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. Blueprints can also be stored in remote [OCI](https://opencontainers.org/) compliant registries. This includes GitHub Container Registry, Docker hub and many other registries.

View File

@ -60,3 +60,7 @@ Used by authentik's packaged blueprints to keep globals up-to-date. Should only
#### `blueprints.goauthentik.io/instantiate`: #### `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. 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.