improved out-of-box experience (#704)

This commit is contained in:
Jens L 2021-04-06 20:25:22 +02:00 committed by GitHub
parent fb409a73a1
commit a2a35e49a9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 321 additions and 74 deletions

View File

@ -1,6 +1,8 @@
# Generated by Django 3.0.6 on 2020-05-23 16:40 # Generated by Django 3.0.6 on 2020-05-23 16:40
from os import environ
from django.apps.registry import Apps from django.apps.registry import Apps
from django.conf import settings
from django.db import migrations, models from django.db import migrations, models
from django.db.backends.base.schema import BaseDatabaseSchemaEditor from django.db.backends.base.schema import BaseDatabaseSchemaEditor
@ -14,7 +16,12 @@ def create_default_user(apps: Apps, schema_editor: BaseDatabaseSchemaEditor):
akadmin, _ = User.objects.using(db_alias).get_or_create( akadmin, _ = User.objects.using(db_alias).get_or_create(
username="akadmin", email="root@localhost", name="authentik Default Admin" username="akadmin", email="root@localhost", name="authentik Default Admin"
) )
akadmin.set_password("akadmin", signal=False) # noqa # nosec if "TF_BUILD" in environ or "AK_ADMIN_PASS" in environ or settings.TEST:
akadmin.set_password(
environ.get("AK_ADMIN_PASS", "akadmin"), signal=False
) # noqa # nosec
else:
akadmin.set_unusable_password()
akadmin.save() akadmin.save()

View File

@ -57,11 +57,12 @@ def progress_bar(
def update_expires(apps: Apps, schema_editor: BaseDatabaseSchemaEditor): def update_expires(apps: Apps, schema_editor: BaseDatabaseSchemaEditor):
db_alias = schema_editor.connection.alias db_alias = schema_editor.connection.alias
print("\nAdding expiry to events, this might take a couple of minutes...")
Event = apps.get_model("authentik_events", "event") Event = apps.get_model("authentik_events", "event")
all_events = Event.objects.using(db_alias).all() all_events = Event.objects.using(db_alias).all()
if all_events.count() < 1:
return
print("\nAdding expiry to events, this might take a couple of minutes...")
for event in progress_bar(all_events): for event in progress_bar(all_events):
event.expires = event.created + timedelta(days=365) event.expires = event.created + timedelta(days=365)
event.save() event.save()

View File

@ -45,7 +45,7 @@ def create_default_source_enrollment_flow(
slug="default-source-enrollment", slug="default-source-enrollment",
designation=FlowDesignation.ENROLLMENT, designation=FlowDesignation.ENROLLMENT,
defaults={ defaults={
"name": "Welcome to authentik!", "name": "Welcome to authentik! Please select a username.",
}, },
) )
PolicyBinding.objects.using(db_alias).update_or_create( PolicyBinding.objects.using(db_alias).update_or_create(
@ -54,7 +54,7 @@ def create_default_source_enrollment_flow(
# PromptStage to ask user for their username # PromptStage to ask user for their username
prompt_stage, _ = PromptStage.objects.using(db_alias).update_or_create( prompt_stage, _ = PromptStage.objects.using(db_alias).update_or_create(
name="Welcome to authentik! Please select a username.", name="default-source-enrollment-prompt",
) )
prompt, _ = Prompt.objects.using(db_alias).update_or_create( prompt, _ = Prompt.objects.using(db_alias).update_or_create(
field_key="username", field_key="username",
@ -63,6 +63,7 @@ def create_default_source_enrollment_flow(
"type": FieldTypes.TEXT, "type": FieldTypes.TEXT,
"required": True, "required": True,
"placeholder": "Username", "placeholder": "Username",
"order": 100,
}, },
) )
prompt_stage.fields.add(prompt) prompt_stage.fields.add(prompt)

View File

@ -8,7 +8,7 @@ def add_title_for_defaults(apps: Apps, schema_editor: BaseDatabaseSchemaEditor):
slug_title_map = { slug_title_map = {
"default-authentication-flow": "Welcome to authentik!", "default-authentication-flow": "Welcome to authentik!",
"default-invalidation-flow": "Default Invalidation Flow", "default-invalidation-flow": "Default Invalidation Flow",
"default-source-enrollment": "Welcome to authentik!", "default-source-enrollment": "Welcome to authentik! Please select a username.",
"default-source-authentication": "Welcome to authentik!", "default-source-authentication": "Welcome to authentik!",
"default-provider-authorization-implicit-consent": "Default Provider Authorization Flow (implicit consent)", "default-provider-authorization-implicit-consent": "Default Provider Authorization Flow (implicit consent)",
"default-provider-authorization-explicit-consent": "Default Provider Authorization Flow (explicit consent)", "default-provider-authorization-explicit-consent": "Default Provider Authorization Flow (explicit consent)",

View File

@ -0,0 +1,139 @@
# Generated by Django 3.1.7 on 2021-04-06 13:25
from django.apps.registry import Apps
from django.contrib.auth.hashers import is_password_usable
from django.db import migrations
from django.db.backends.base.schema import BaseDatabaseSchemaEditor
from authentik.flows.models import FlowDesignation
PW_USABLE_POLICY_EXPRESSION = """# This policy ensures that the setup flow can only be
# executed when the admin user doesn't have a password set
akadmin = ak_user_by(username="akadmin")
return not akadmin.has_usable_password()"""
PREFILL_POLICY_EXPRESSION = """# This policy sets the user for the currently running flow
# by injecting "pending_user"
akadmin = ak_user_by(username="akadmin")
context["pending_user"] = akadmin
# We're also setting the backend for the user, so we can
# directly login without having to identify again
context["user_backend"] = "django.contrib.auth.backends.ModelBackend"
return True"""
def create_default_oob_flow(apps: Apps, schema_editor: BaseDatabaseSchemaEditor):
from authentik.stages.prompt.models import FieldTypes
User = apps.get_model("authentik_core", "User")
PolicyBinding = apps.get_model("authentik_policies", "PolicyBinding")
Flow = apps.get_model("authentik_flows", "Flow")
FlowStageBinding = apps.get_model("authentik_flows", "FlowStageBinding")
UserLoginStage = apps.get_model("authentik_stages_user_login", "UserLoginStage")
UserWriteStage = apps.get_model("authentik_stages_user_write", "UserWriteStage")
PromptStage = apps.get_model("authentik_stages_prompt", "PromptStage")
Prompt = apps.get_model("authentik_stages_prompt", "Prompt")
ExpressionPolicy = apps.get_model(
"authentik_policies_expression", "ExpressionPolicy"
)
db_alias = schema_editor.connection.alias
# Only create the flow if the akadmin user exists,
# and has an un-usable password
akadmins = User.objects.filter(username="akadmin")
if not akadmins.exists():
return
akadmin = akadmins.first()
if is_password_usable(akadmin.password):
return
# Create a policy that sets the flow's user
prefill_policy, _ = ExpressionPolicy.objects.using(db_alias).update_or_create(
name="default-oob-prefill-user",
defaults={"expression": PREFILL_POLICY_EXPRESSION},
)
password_usable_policy, _ = ExpressionPolicy.objects.using(
db_alias
).update_or_create(
name="default-oob-password-usable",
defaults={"expression": PW_USABLE_POLICY_EXPRESSION},
)
prompt_header, _ = Prompt.objects.using(db_alias).update_or_create(
field_key="oob-header-text",
defaults={
"label": "oob-header-text",
"type": FieldTypes.STATIC,
"placeholder": "Welcome to authentik! Please set a password for the default admin user, akadmin.",
"order": 100,
},
)
password_first = Prompt.objects.using(db_alias).get(field_key="password")
password_second = Prompt.objects.using(db_alias).get(field_key="password_repeat")
prompt_stage, _ = PromptStage.objects.using(db_alias).update_or_create(
name="default-oob-password",
)
prompt_stage.fields.set([prompt_header, password_first, password_second])
prompt_stage.save()
user_write, _ = UserWriteStage.objects.using(db_alias).update_or_create(
name="default-password-change-write"
)
login_stage, _ = UserLoginStage.objects.using(db_alias).update_or_create(
name="default-authentication-login"
)
flow, _ = Flow.objects.using(db_alias).update_or_create(
slug="initial-setup",
designation=FlowDesignation.STAGE_CONFIGURATION,
defaults={
"name": "default-oob-setup",
"title": "Welcome to authentik!",
},
)
PolicyBinding.objects.using(db_alias).update_or_create(
policy=password_usable_policy, target=flow, defaults={"order": 0}
)
FlowStageBinding.objects.using(db_alias).update_or_create(
target=flow,
stage=prompt_stage,
defaults={
"order": 10,
},
)
user_write_binding, _ = FlowStageBinding.objects.using(db_alias).update_or_create(
target=flow,
stage=user_write,
defaults={"order": 20, "evaluate_on_plan": False, "re_evaluate_policies": True},
)
PolicyBinding.objects.using(db_alias).update_or_create(
policy=prefill_policy, target=user_write_binding, defaults={"order": 0}
)
FlowStageBinding.objects.using(db_alias).update_or_create(
target=flow,
stage=login_stage,
defaults={
"order": 100,
},
)
class Migration(migrations.Migration):
dependencies = [
("authentik_flows", "0017_auto_20210329_1334"),
("authentik_stages_user_write", "__latest__"),
("authentik_stages_user_login", "__latest__"),
("authentik_stages_password", "0002_passwordstage_change_flow"),
("authentik_policies", "0001_initial"),
("authentik_policies_expression", "0001_initial"),
]
operations = [
migrations.RunPython(create_default_oob_flow),
]

View File

@ -36,7 +36,7 @@ def create_default_password_change(apps: Apps, schema_editor: BaseDatabaseSchema
"type": FieldTypes.PASSWORD, "type": FieldTypes.PASSWORD,
"required": True, "required": True,
"placeholder": "Password", "placeholder": "Password",
"order": 0, "order": 300,
}, },
) )
password_rep_prompt, _ = Prompt.objects.using(db_alias).update_or_create( password_rep_prompt, _ = Prompt.objects.using(db_alias).update_or_create(
@ -46,7 +46,7 @@ def create_default_password_change(apps: Apps, schema_editor: BaseDatabaseSchema
"type": FieldTypes.PASSWORD, "type": FieldTypes.PASSWORD,
"required": True, "required": True,
"placeholder": "Password (repeat)", "placeholder": "Password (repeat)",
"order": 1, "order": 301,
}, },
) )

View File

@ -30,7 +30,7 @@ class PromptSerializer(PassiveSerializer):
"""Serializer for a single Prompt field""" """Serializer for a single Prompt field"""
field_key = CharField() field_key = CharField()
label = CharField() label = CharField(allow_blank=True)
type = CharField() type = CharField()
required = BooleanField() required = BooleanField()
placeholder = CharField() placeholder = CharField()

View File

@ -69,6 +69,10 @@ class UserWriteStageView(StageView):
LOGGER.debug("discarding key", key=key) LOGGER.debug("discarding key", key=key)
continue continue
user.attributes[key.replace("attribute_", "", 1)] = value user.attributes[key.replace("attribute_", "", 1)] = value
# Extra check to prevent flows from saving a user with a blank username
if user.username == "":
LOGGER.warning("Aborting write to empty username", user=user)
return self.executor.stage_invalid()
user.save() user.save()
user_write.send( user_write.send(
sender=self, request=request, user=user, data=data, created=user_created sender=self, request=request, user=user, data=data, created=user_created

View File

@ -134,3 +134,36 @@ class TestUserWriteStage(TestCase):
"type": ChallengeTypes.NATIVE.value, "type": ChallengeTypes.NATIVE.value,
}, },
) )
@patch(
"authentik.flows.views.to_stage_response",
TO_STAGE_RESPONSE_MOCK,
)
def test_with_blank_username(self):
"""Test with blank username results in error"""
plan = FlowPlan(
flow_pk=self.flow.pk.hex, stages=[self.stage], markers=[StageMarker()]
)
session = self.client.session
plan.context[PLAN_CONTEXT_PROMPT] = {
"username": "",
"attribute_some-custom-attribute": "test",
"some_ignored_attribute": "bar",
}
session[SESSION_KEY_PLAN] = plan
session.save()
response = self.client.get(
reverse("authentik_api:flow-executor", kwargs={"flow_slug": self.flow.slug})
)
self.assertEqual(response.status_code, 200)
self.assertJSONEqual(
force_str(response.content),
{
"component": "ak-stage-access-denied",
"error_message": None,
"title": "",
"type": ChallengeTypes.NATIVE.value,
},
)

View File

@ -1,5 +1,11 @@
1. Access authentik using the following URL: Access authentik using the following URL:
{{- if .Release.IsUpgrade -}}
{{- range .Values.ingress.hosts }} {{- range .Values.ingress.hosts }}
http{{ if $.Values.ingress.tls }}s{{ end }}://{{ . }}{{ $.Values.ingress.path }} http{{ if $.Values.ingress.tls }}s{{ end }}://{{ . }}{{ $.Values.ingress.path }}
{{- end }} {{- end }}
2. Login to authentik using the user "akadmin" and the password "akadmin". {{- else -}}
{{- range .Values.ingress.hosts }}
http{{ if $.Values.ingress.tls }}s{{ end }}://{{ . }}{{ $.Values.ingress.path }}/if/flow/initial-setup/
{{- end }}
To configure your authentik instance, and set a password for the akadmin user.
{{- end }}

View File

@ -78,8 +78,7 @@ export class MessageContainer extends LitElement {
this.addMessage(data); this.addMessage(data);
this.requestUpdate(); this.requestUpdate();
}); });
this.messageSocket.addEventListener("error", (e) => { this.messageSocket.addEventListener("error", () => {
console.warn(`authentik/messages: error ${e}`);
this.retryDelay = this.retryDelay * 2; this.retryDelay = this.retryDelay * 2;
}); });
} }

View File

@ -6,6 +6,7 @@ import PFBase from "@patternfly/patternfly/patternfly-base.css";
import PFTitle from "@patternfly/patternfly/components/Title/title.css"; import PFTitle from "@patternfly/patternfly/components/Title/title.css";
import PFBackgroundImage from "@patternfly/patternfly/components/BackgroundImage/background-image.css"; import PFBackgroundImage from "@patternfly/patternfly/components/BackgroundImage/background-image.css";
import PFList from "@patternfly/patternfly/components/List/list.css"; import PFList from "@patternfly/patternfly/components/List/list.css";
import PFButton from "@patternfly/patternfly/components/Button/button.css";
import AKGlobal from "../authentik.css"; import AKGlobal from "../authentik.css";
import { unsafeHTML } from "lit-html/directives/unsafe-html"; import { unsafeHTML } from "lit-html/directives/unsafe-html";
@ -58,7 +59,7 @@ export class FlowExecutor extends LitElement implements StageHost {
config?: Config; config?: Config;
static get styles(): CSSResult[] { static get styles(): CSSResult[] {
return [PFBase, PFLogin, PFTitle, PFList, PFBackgroundImage, AKGlobal].concat(css` return [PFBase, PFLogin, PFButton, PFTitle, PFList, PFBackgroundImage, AKGlobal].concat(css`
.ak-loading { .ak-loading {
display: flex; display: flex;
height: 100%; height: 100%;
@ -115,8 +116,8 @@ export class FlowExecutor extends LitElement implements StageHost {
}).then((data) => { }).then((data) => {
this.challenge = data; this.challenge = data;
this.postUpdate(); this.postUpdate();
}).catch((e) => { }).catch((e: Response) => {
this.errorMessage(e); this.errorMessage(e.statusText);
}).finally(() => { }).finally(() => {
this.loading = false; this.loading = false;
}); });
@ -139,9 +140,9 @@ export class FlowExecutor extends LitElement implements StageHost {
this.setBackground(this.challenge.background); this.setBackground(this.challenge.background);
} }
this.postUpdate(); this.postUpdate();
}).catch((e) => { }).catch((e: Response) => {
// Catch JSON or Update errors // Catch JSON or Update errors
this.errorMessage(e); this.errorMessage(e.statusText);
}).finally(() => { }).finally(() => {
this.loading = false; this.loading = false;
}); });
@ -158,7 +159,16 @@ export class FlowExecutor extends LitElement implements StageHost {
<div class="pf-c-login__main-body"> <div class="pf-c-login__main-body">
<h3>${t`Something went wrong! Please try again later.`}</h3> <h3>${t`Something went wrong! Please try again later.`}</h3>
<pre class="ak-exception">${error}</pre> <pre class="ak-exception">${error}</pre>
</div>` </div>
<footer class="pf-c-login__main-footer">
<ul class="pf-c-login__main-footer-links">
<li class="pf-c-login__main-footer-links-item">
<a class="pf-c-button pf-m-primary pf-m-block" href="/">
${t`Return`}
</a>
</li>
</ul>
</footer>`
}; };
} }

View File

@ -7,11 +7,13 @@ import PFFormControl from "@patternfly/patternfly/components/FormControl/form-co
import PFTitle from "@patternfly/patternfly/components/Title/title.css"; import PFTitle from "@patternfly/patternfly/components/Title/title.css";
import PFButton from "@patternfly/patternfly/components/Button/button.css"; import PFButton from "@patternfly/patternfly/components/Button/button.css";
import PFBase from "@patternfly/patternfly/patternfly-base.css"; import PFBase from "@patternfly/patternfly/patternfly-base.css";
import PFAlert from "@patternfly/patternfly/components/Alert/alert.css";
import AKGlobal from "../../../authentik.css"; import AKGlobal from "../../../authentik.css";
import { BaseStage } from "../base"; import { BaseStage } from "../base";
import "../../../elements/forms/FormElement"; import "../../../elements/forms/FormElement";
import "../../../elements/EmptyState"; import "../../../elements/EmptyState";
import { Challenge } from "../../../api/Flows"; import "../../../elements/Divider";
import { Challenge, Error } from "../../../api/Flows";
export interface Prompt { export interface Prompt {
field_key: string; field_key: string;
@ -33,7 +35,7 @@ export class PromptStage extends BaseStage {
challenge?: PromptChallenge; challenge?: PromptChallenge;
static get styles(): CSSResult[] { static get styles(): CSSResult[] {
return [PFBase, PFLogin, PFForm, PFFormControl, PFTitle, PFButton, AKGlobal]; return [PFBase, PFLogin, PFAlert, PFForm, PFFormControl, PFTitle, PFButton, AKGlobal];
} }
renderPromptInner(prompt: Prompt): string { renderPromptInner(prompt: Prompt): string {
@ -101,7 +103,7 @@ export class PromptStage extends BaseStage {
class="pf-c-form-control" class="pf-c-form-control"
?required=${prompt.required}>`; ?required=${prompt.required}>`;
case "separator": case "separator":
return "<hr>"; return `<ak-divider>${prompt.placeholder}</ak-divider>`;
case "hidden": case "hidden":
return `<input return `<input
type="hidden" type="hidden"
@ -110,13 +112,29 @@ export class PromptStage extends BaseStage {
class="pf-c-form-control" class="pf-c-form-control"
?required=${prompt.required}>`; ?required=${prompt.required}>`;
case "static": case "static":
return `<p return `<p>${prompt.placeholder}</p>`;
class="pf-c-form-control">${prompt.placeholder}
</p>`;
} }
return ""; return "";
} }
renderNonFieldErrors(errors: Error[]): TemplateResult {
if (!errors) {
return html``;
}
return html`<div class="pf-c-form__alert">
${errors.map(err => {
return html`<div class="pf-c-alert pf-m-inline pf-m-danger">
<div class="pf-c-alert__icon">
<i class="fas fa-exclamation-circle"></i>
</div>
<h4 class="pf-c-alert__title">
${err.string}
</h4>
</div>`;
})}
</div>`;
}
render(): TemplateResult { render(): TemplateResult {
if (!this.challenge) { if (!this.challenge) {
return html`<ak-empty-state return html`<ak-empty-state
@ -132,6 +150,10 @@ export class PromptStage extends BaseStage {
<div class="pf-c-login__main-body"> <div class="pf-c-login__main-body">
<form class="pf-c-form" @submit=${(e: Event) => {this.submitForm(e);}}> <form class="pf-c-form" @submit=${(e: Event) => {this.submitForm(e);}}>
${this.challenge.fields.map((prompt) => { ${this.challenge.fields.map((prompt) => {
// Special types that aren't rendered in a wrapper
if (prompt.type === "static" || prompt.type === "hidden" || prompt.type === "separator") {
return unsafeHTML(this.renderPromptInner(prompt));
}
return html`<ak-form-element return html`<ak-form-element
label="${prompt.label}" label="${prompt.label}"
?required="${prompt.required}" ?required="${prompt.required}"
@ -140,6 +162,9 @@ export class PromptStage extends BaseStage {
${unsafeHTML(this.renderPromptInner(prompt))} ${unsafeHTML(this.renderPromptInner(prompt))}
</ak-form-element>`; </ak-form-element>`;
})} })}
${"non_field_errors" in (this.challenge?.response_errors || {}) ?
this.renderNonFieldErrors(this.challenge?.response_errors?.non_field_errors || []):
html``}
<div class="pf-c-form__group pf-m-action"> <div class="pf-c-form__group pf-m-action">
<button type="submit" class="pf-c-button pf-m-primary pf-m-block"> <button type="submit" class="pf-c-button pf-m-primary pf-m-block">
${t`Continue`} ${t`Continue`}

View File

@ -32,16 +32,22 @@ msgstr "ACS URL"
#: src/pages/applications/ApplicationForm.ts:110 #: src/pages/applications/ApplicationForm.ts:110
#: src/pages/flows/FlowForm.ts:109 #: src/pages/flows/FlowForm.ts:109
#: src/pages/flows/StageBindingForm.ts:142
msgid "ALL, all policies must match to grant access." msgid "ALL, all policies must match to grant access."
msgstr "ALL, all policies must match to grant access." msgstr "ALL, all policies must match to grant access."
#: src/pages/flows/StageBindingForm.ts:144
msgid "ALL, all policies must match to include this stage access."
msgstr "ALL, all policies must match to include this stage access."
#: src/pages/applications/ApplicationForm.ts:107 #: src/pages/applications/ApplicationForm.ts:107
#: src/pages/flows/FlowForm.ts:106 #: src/pages/flows/FlowForm.ts:106
#: src/pages/flows/StageBindingForm.ts:139
msgid "ANY, any policy must match to grant access." msgid "ANY, any policy must match to grant access."
msgstr "ANY, any policy must match to grant access." msgstr "ANY, any policy must match to grant access."
#: src/pages/flows/StageBindingForm.ts:141
msgid "ANY, any policy must match to include this stage access."
msgstr "ANY, any policy must match to include this stage access."
#: src/elements/notifications/APIDrawer.ts:61 #: src/elements/notifications/APIDrawer.ts:61
msgid "API Requests" msgid "API Requests"
msgstr "API Requests" msgstr "API Requests"
@ -625,7 +631,7 @@ msgstr "Context"
#: src/flows/stages/consent/ConsentStage.ts:60 #: src/flows/stages/consent/ConsentStage.ts:60
#: src/flows/stages/dummy/DummyStage.ts:39 #: src/flows/stages/dummy/DummyStage.ts:39
#: src/flows/stages/password/PasswordStage.ts:71 #: src/flows/stages/password/PasswordStage.ts:71
#: src/flows/stages/prompt/PromptStage.ts:130 #: src/flows/stages/prompt/PromptStage.ts:155
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts:91 #: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts:91
msgid "Continue" msgid "Continue"
msgstr "Continue" msgstr "Continue"
@ -1084,17 +1090,17 @@ msgstr "Error: unsupported source settings: {0}"
msgid "Error: unsupported stage settings: {0}" msgid "Error: unsupported stage settings: {0}"
msgstr "Error: unsupported stage settings: {0}" msgstr "Error: unsupported stage settings: {0}"
#: src/pages/flows/StageBindingForm.ts:113 #: src/pages/flows/StageBindingForm.ts:119
msgid "Evaluate on plan" msgid "Evaluate on plan"
msgstr "Evaluate on plan" msgstr "Evaluate on plan"
#: src/pages/flows/StageBindingForm.ts:116 #: src/pages/flows/StageBindingForm.ts:133
msgid "Evaluate policies during the Flow planning process. Disable this for input-based policies." msgid "Evaluate policies before the Stage is present to the user."
msgstr "Evaluate policies during the Flow planning process. Disable this for input-based policies." msgstr "Evaluate policies before the Stage is present to the user."
#: src/pages/flows/StageBindingForm.ts:125 #: src/pages/flows/StageBindingForm.ts:123
msgid "Evaluate policies when the Stage is present to the user." msgid "Evaluate policies during the Flow planning process. Disable this for input-based policies. Should be used in conjunction with 'Re-evaluate policies', as with this option disabled, policies are **not** evaluated."
msgstr "Evaluate policies when the Stage is present to the user." msgstr "Evaluate policies during the Flow planning process. Disable this for input-based policies. Should be used in conjunction with 'Re-evaluate policies', as with this option disabled, policies are **not** evaluated."
#: src/pages/events/EventListPage.ts:22 #: src/pages/events/EventListPage.ts:22
msgid "Event Log" msgid "Event Log"
@ -1594,8 +1600,8 @@ msgid "Library"
msgstr "Library" msgstr "Library"
#: src/elements/table/Table.ts:113 #: src/elements/table/Table.ts:113
#: src/flows/FlowExecutor.ts:154 #: src/flows/FlowExecutor.ts:164
#: src/flows/FlowExecutor.ts:200 #: src/flows/FlowExecutor.ts:210
#: src/flows/access_denied/FlowAccessDenied.ts:27 #: src/flows/access_denied/FlowAccessDenied.ts:27
#: src/flows/stages/authenticator_static/AuthenticatorStaticStage.ts:43 #: src/flows/stages/authenticator_static/AuthenticatorStaticStage.ts:43
#: src/flows/stages/authenticator_totp/AuthenticatorTOTPStage.ts:33 #: src/flows/stages/authenticator_totp/AuthenticatorTOTPStage.ts:33
@ -1608,7 +1614,7 @@ msgstr "Library"
#: src/flows/stages/email/EmailStage.ts:26 #: src/flows/stages/email/EmailStage.ts:26
#: src/flows/stages/identification/IdentificationStage.ts:134 #: src/flows/stages/identification/IdentificationStage.ts:134
#: src/flows/stages/password/PasswordStage.ts:31 #: src/flows/stages/password/PasswordStage.ts:31
#: src/flows/stages/prompt/PromptStage.ts:108 #: src/flows/stages/prompt/PromptStage.ts:126
#: src/pages/applications/ApplicationViewPage.ts:55 #: src/pages/applications/ApplicationViewPage.ts:55
#: src/pages/user-settings/UserDetailsPage.ts:38 #: src/pages/user-settings/UserDetailsPage.ts:38
#: src/utils.ts:40 #: src/utils.ts:40
@ -2072,7 +2078,7 @@ msgid "Optionally set the 'FriendlyName' value of the Assertion attribute."
msgstr "Optionally set the 'FriendlyName' value of the Assertion attribute." msgstr "Optionally set the 'FriendlyName' value of the Assertion attribute."
#: src/pages/flows/BoundStagesList.ts:38 #: src/pages/flows/BoundStagesList.ts:38
#: src/pages/flows/StageBindingForm.ts:128 #: src/pages/flows/StageBindingForm.ts:110
#: src/pages/policies/BoundPoliciesList.ts:38 #: src/pages/policies/BoundPoliciesList.ts:38
#: src/pages/policies/PolicyBindingForm.ts:203 #: src/pages/policies/PolicyBindingForm.ts:203
#: src/pages/stages/prompt/PromptForm.ts:119 #: src/pages/stages/prompt/PromptForm.ts:119
@ -2199,7 +2205,7 @@ msgstr "Policy binding"
#: src/pages/applications/ApplicationForm.ts:102 #: src/pages/applications/ApplicationForm.ts:102
#: src/pages/flows/FlowForm.ts:101 #: src/pages/flows/FlowForm.ts:101
#: src/pages/flows/StageBindingForm.ts:134 #: src/pages/flows/StageBindingForm.ts:136
msgid "Policy engine mode" msgid "Policy engine mode"
msgstr "Policy engine mode" msgstr "Policy engine mode"
@ -2229,7 +2235,7 @@ msgstr "Post binding"
msgid "Post binding (auto-submit)" msgid "Post binding (auto-submit)"
msgstr "Post binding (auto-submit)" msgstr "Post binding (auto-submit)"
#: src/flows/FlowExecutor.ts:242 #: src/flows/FlowExecutor.ts:252
msgid "Powered by authentik" msgid "Powered by authentik"
msgstr "Powered by authentik" msgstr "Powered by authentik"
@ -2374,7 +2380,7 @@ msgstr "RSA-SHA384"
msgid "RSA-SHA512" msgid "RSA-SHA512"
msgstr "RSA-SHA512" msgstr "RSA-SHA512"
#: src/pages/flows/StageBindingForm.ts:122 #: src/pages/flows/StageBindingForm.ts:130
msgid "Re-evaluate policies" msgid "Re-evaluate policies"
msgstr "Re-evaluate policies" msgstr "Re-evaluate policies"
@ -2469,6 +2475,10 @@ msgstr "Retry Task"
msgid "Retry authentication" msgid "Retry authentication"
msgstr "Retry authentication" msgstr "Retry authentication"
#: src/flows/FlowExecutor.ts:142
msgid "Return"
msgstr "Return"
#: src/elements/router/Router404.ts:28 #: src/elements/router/Router404.ts:28
msgid "Return home" msgid "Return home"
msgstr "Return home" msgstr "Return home"
@ -2701,7 +2711,7 @@ msgstr "Skip path regex"
msgid "Slug" msgid "Slug"
msgstr "Slug" msgstr "Slug"
#: src/flows/FlowExecutor.ts:134 #: src/flows/FlowExecutor.ts:135
msgid "Something went wrong! Please try again later." msgid "Something went wrong! Please try again later."
msgstr "Something went wrong! Please try again later." msgstr "Something went wrong! Please try again later."
@ -3662,7 +3672,7 @@ msgstr "When selected, incoming assertion's Signatures will be validated against
msgid "When this option is enabled, all executions of this policy will be logged. By default, only execution errors are logged." msgid "When this option is enabled, all executions of this policy will be logged. By default, only execution errors are logged."
msgstr "When this option is enabled, all executions of this policy will be logged. By default, only execution errors are logged." msgstr "When this option is enabled, all executions of this policy will be logged. By default, only execution errors are logged."
#: src/flows/FlowExecutor.ts:130 #: src/flows/FlowExecutor.ts:131
msgid "Whoops!" msgid "Whoops!"
msgstr "Whoops!" msgstr "Whoops!"

View File

@ -32,16 +32,22 @@ msgstr ""
#: src/pages/applications/ApplicationForm.ts:110 #: src/pages/applications/ApplicationForm.ts:110
#: src/pages/flows/FlowForm.ts:109 #: src/pages/flows/FlowForm.ts:109
#: src/pages/flows/StageBindingForm.ts:142
msgid "ALL, all policies must match to grant access." msgid "ALL, all policies must match to grant access."
msgstr "" msgstr ""
#: src/pages/flows/StageBindingForm.ts:144
msgid "ALL, all policies must match to include this stage access."
msgstr ""
#: src/pages/applications/ApplicationForm.ts:107 #: src/pages/applications/ApplicationForm.ts:107
#: src/pages/flows/FlowForm.ts:106 #: src/pages/flows/FlowForm.ts:106
#: src/pages/flows/StageBindingForm.ts:139
msgid "ANY, any policy must match to grant access." msgid "ANY, any policy must match to grant access."
msgstr "" msgstr ""
#: src/pages/flows/StageBindingForm.ts:141
msgid "ANY, any policy must match to include this stage access."
msgstr ""
#: src/elements/notifications/APIDrawer.ts:61 #: src/elements/notifications/APIDrawer.ts:61
msgid "API Requests" msgid "API Requests"
msgstr "" msgstr ""
@ -621,7 +627,7 @@ msgstr ""
#: src/flows/stages/consent/ConsentStage.ts:60 #: src/flows/stages/consent/ConsentStage.ts:60
#: src/flows/stages/dummy/DummyStage.ts:39 #: src/flows/stages/dummy/DummyStage.ts:39
#: src/flows/stages/password/PasswordStage.ts:71 #: src/flows/stages/password/PasswordStage.ts:71
#: src/flows/stages/prompt/PromptStage.ts:130 #: src/flows/stages/prompt/PromptStage.ts:155
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts:91 #: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts:91
msgid "Continue" msgid "Continue"
msgstr "" msgstr ""
@ -1080,16 +1086,16 @@ msgstr ""
msgid "Error: unsupported stage settings: {0}" msgid "Error: unsupported stage settings: {0}"
msgstr "" msgstr ""
#: src/pages/flows/StageBindingForm.ts:113 #: src/pages/flows/StageBindingForm.ts:119
msgid "Evaluate on plan" msgid "Evaluate on plan"
msgstr "" msgstr ""
#: src/pages/flows/StageBindingForm.ts:116 #: src/pages/flows/StageBindingForm.ts:133
msgid "Evaluate policies during the Flow planning process. Disable this for input-based policies." msgid "Evaluate policies before the Stage is present to the user."
msgstr "" msgstr ""
#: src/pages/flows/StageBindingForm.ts:125 #: src/pages/flows/StageBindingForm.ts:123
msgid "Evaluate policies when the Stage is present to the user." msgid "Evaluate policies during the Flow planning process. Disable this for input-based policies. Should be used in conjunction with 'Re-evaluate policies', as with this option disabled, policies are **not** evaluated."
msgstr "" msgstr ""
#: src/pages/events/EventListPage.ts:22 #: src/pages/events/EventListPage.ts:22
@ -1590,8 +1596,8 @@ msgid "Library"
msgstr "" msgstr ""
#: src/elements/table/Table.ts:113 #: src/elements/table/Table.ts:113
#: src/flows/FlowExecutor.ts:154 #: src/flows/FlowExecutor.ts:164
#: src/flows/FlowExecutor.ts:200 #: src/flows/FlowExecutor.ts:210
#: src/flows/access_denied/FlowAccessDenied.ts:27 #: src/flows/access_denied/FlowAccessDenied.ts:27
#: src/flows/stages/authenticator_static/AuthenticatorStaticStage.ts:43 #: src/flows/stages/authenticator_static/AuthenticatorStaticStage.ts:43
#: src/flows/stages/authenticator_totp/AuthenticatorTOTPStage.ts:33 #: src/flows/stages/authenticator_totp/AuthenticatorTOTPStage.ts:33
@ -1604,7 +1610,7 @@ msgstr ""
#: src/flows/stages/email/EmailStage.ts:26 #: src/flows/stages/email/EmailStage.ts:26
#: src/flows/stages/identification/IdentificationStage.ts:134 #: src/flows/stages/identification/IdentificationStage.ts:134
#: src/flows/stages/password/PasswordStage.ts:31 #: src/flows/stages/password/PasswordStage.ts:31
#: src/flows/stages/prompt/PromptStage.ts:108 #: src/flows/stages/prompt/PromptStage.ts:126
#: src/pages/applications/ApplicationViewPage.ts:55 #: src/pages/applications/ApplicationViewPage.ts:55
#: src/pages/user-settings/UserDetailsPage.ts:38 #: src/pages/user-settings/UserDetailsPage.ts:38
#: src/utils.ts:40 #: src/utils.ts:40
@ -2068,7 +2074,7 @@ msgid "Optionally set the 'FriendlyName' value of the Assertion attribute."
msgstr "" msgstr ""
#: src/pages/flows/BoundStagesList.ts:38 #: src/pages/flows/BoundStagesList.ts:38
#: src/pages/flows/StageBindingForm.ts:128 #: src/pages/flows/StageBindingForm.ts:110
#: src/pages/policies/BoundPoliciesList.ts:38 #: src/pages/policies/BoundPoliciesList.ts:38
#: src/pages/policies/PolicyBindingForm.ts:203 #: src/pages/policies/PolicyBindingForm.ts:203
#: src/pages/stages/prompt/PromptForm.ts:119 #: src/pages/stages/prompt/PromptForm.ts:119
@ -2195,7 +2201,7 @@ msgstr ""
#: src/pages/applications/ApplicationForm.ts:102 #: src/pages/applications/ApplicationForm.ts:102
#: src/pages/flows/FlowForm.ts:101 #: src/pages/flows/FlowForm.ts:101
#: src/pages/flows/StageBindingForm.ts:134 #: src/pages/flows/StageBindingForm.ts:136
msgid "Policy engine mode" msgid "Policy engine mode"
msgstr "" msgstr ""
@ -2225,7 +2231,7 @@ msgstr ""
msgid "Post binding (auto-submit)" msgid "Post binding (auto-submit)"
msgstr "" msgstr ""
#: src/flows/FlowExecutor.ts:242 #: src/flows/FlowExecutor.ts:252
msgid "Powered by authentik" msgid "Powered by authentik"
msgstr "" msgstr ""
@ -2370,7 +2376,7 @@ msgstr ""
msgid "RSA-SHA512" msgid "RSA-SHA512"
msgstr "" msgstr ""
#: src/pages/flows/StageBindingForm.ts:122 #: src/pages/flows/StageBindingForm.ts:130
msgid "Re-evaluate policies" msgid "Re-evaluate policies"
msgstr "" msgstr ""
@ -2465,6 +2471,10 @@ msgstr ""
msgid "Retry authentication" msgid "Retry authentication"
msgstr "" msgstr ""
#: src/flows/FlowExecutor.ts:142
msgid "Return"
msgstr ""
#: src/elements/router/Router404.ts:28 #: src/elements/router/Router404.ts:28
msgid "Return home" msgid "Return home"
msgstr "" msgstr ""
@ -2697,7 +2707,7 @@ msgstr ""
msgid "Slug" msgid "Slug"
msgstr "" msgstr ""
#: src/flows/FlowExecutor.ts:134 #: src/flows/FlowExecutor.ts:135
msgid "Something went wrong! Please try again later." msgid "Something went wrong! Please try again later."
msgstr "" msgstr ""
@ -3656,7 +3666,7 @@ msgstr ""
msgid "When this option is enabled, all executions of this policy will be logged. By default, only execution errors are logged." msgid "When this option is enabled, all executions of this policy will be logged. By default, only execution errors are logged."
msgstr "" msgstr ""
#: src/flows/FlowExecutor.ts:130 #: src/flows/FlowExecutor.ts:131
msgid "Whoops!" msgid "Whoops!"
msgstr "" msgstr ""

View File

@ -106,6 +106,12 @@ export class StageBindingForm extends Form<FlowStageBinding> {
}), html`<option>${t`Loading...`}</option>`)} }), html`<option>${t`Loading...`}</option>`)}
</select> </select>
</ak-form-element-horizontal> </ak-form-element-horizontal>
<ak-form-element-horizontal
label=${t`Order`}
?required=${true}
name="order">
<input type="number" value="${until(this.getOrder())}" class="pf-c-form-control" required>
</ak-form-element-horizontal>
<ak-form-element-horizontal name="evaluateOnPlan"> <ak-form-element-horizontal name="evaluateOnPlan">
<div class="pf-c-check"> <div class="pf-c-check">
<input type="checkbox" class="pf-c-check__input" ?checked=${first(this.fsb?.evaluateOnPlan, true)}> <input type="checkbox" class="pf-c-check__input" ?checked=${first(this.fsb?.evaluateOnPlan, true)}>
@ -113,7 +119,9 @@ export class StageBindingForm extends Form<FlowStageBinding> {
${t`Evaluate on plan`} ${t`Evaluate on plan`}
</label> </label>
</div> </div>
<p class="pf-c-form__helper-text">${t`Evaluate policies during the Flow planning process. Disable this for input-based policies.`}</p> <p class="pf-c-form__helper-text">
${t`Evaluate policies during the Flow planning process. Disable this for input-based policies. Should be used in conjunction with 'Re-evaluate policies', as with this option disabled, policies are **not** evaluated.`}
</p>
</ak-form-element-horizontal> </ak-form-element-horizontal>
<ak-form-element-horizontal name="reEvaluatePolicies"> <ak-form-element-horizontal name="reEvaluatePolicies">
<div class="pf-c-check"> <div class="pf-c-check">
@ -122,13 +130,7 @@ export class StageBindingForm extends Form<FlowStageBinding> {
${t`Re-evaluate policies`} ${t`Re-evaluate policies`}
</label> </label>
</div> </div>
<p class="pf-c-form__helper-text">${t`Evaluate policies when the Stage is present to the user.`}</p> <p class="pf-c-form__helper-text">${t`Evaluate policies before the Stage is present to the user.`}</p>
</ak-form-element-horizontal>
<ak-form-element-horizontal
label=${t`Order`}
?required=${true}
name="order">
<input type="number" value="${until(this.getOrder())}" class="pf-c-form-control" required>
</ak-form-element-horizontal> </ak-form-element-horizontal>
<ak-form-element-horizontal <ak-form-element-horizontal
label=${t`Policy engine mode`} label=${t`Policy engine mode`}
@ -136,10 +138,10 @@ export class StageBindingForm extends Form<FlowStageBinding> {
name="policyEngineMode"> name="policyEngineMode">
<select class="pf-c-form-control"> <select class="pf-c-form-control">
<option value=${FlowStageBindingPolicyEngineModeEnum.Any} ?selected=${this.fsb?.policyEngineMode === FlowStageBindingPolicyEngineModeEnum.Any}> <option value=${FlowStageBindingPolicyEngineModeEnum.Any} ?selected=${this.fsb?.policyEngineMode === FlowStageBindingPolicyEngineModeEnum.Any}>
${t`ANY, any policy must match to grant access.`} ${t`ANY, any policy must match to include this stage access.`}
</option> </option>
<option value=${FlowStageBindingPolicyEngineModeEnum.All} ?selected=${this.fsb?.policyEngineMode === FlowStageBindingPolicyEngineModeEnum.All}> <option value=${FlowStageBindingPolicyEngineModeEnum.All} ?selected=${this.fsb?.policyEngineMode === FlowStageBindingPolicyEngineModeEnum.All}>
${t`ALL, all policies must match to grant access.`} ${t`ALL, all policies must match to include this stage access.`}
</option> </option>
</select> </select>
</ak-form-element-horizontal> </ak-form-element-horizontal>

View File

@ -78,4 +78,4 @@ The compose file statically references the latest version available at the time
authentik will then be reachable HTTPS on port 443. You can optionally configure the packaged traefik to use Let's Encrypt certificates for TLS Encryption. authentik will then be reachable HTTPS on port 443. You can optionally configure the packaged traefik to use Let's Encrypt certificates for TLS Encryption.
The initial setup process also creates a default admin user, the username and password for which is `akadmin`. It is highly recommended to change this password as soon as you log in. To start the initial setup, navigate to `https://<your server>/if/flow/initial-setup/`. There you will be prompted to set a password for the akadmin user.

View File

@ -12,7 +12,7 @@ helm repo update
helm install authentik/authentik --devel -f values.yaml helm install authentik/authentik --devel -f values.yaml
``` ```
This installation automatically applies database migrations on startup. After the installation is done, you can use `akadmin` as username and password. This installation automatically applies database migrations on startup. After the installation is done, navigate to the `https://<ingress you've specified>/if/flow/initial-setup/`, to set a password for the akadmin user.
It is also recommended to configure global email credentials. These are used by authentik to notify you about alerts, configuration issues. They can also be used by [Email stages](flow/stages/email/index.md) to send verification/recovery emails. It is also recommended to configure global email credentials. These are used by authentik to notify you about alerts, configuration issues. They can also be used by [Email stages](flow/stages/email/index.md) to send verification/recovery emails.