stages/identification: make shown sources configurable
closes #918 Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
This commit is contained in:
parent
250e23408e
commit
c4453f38a2
|
@ -17,6 +17,7 @@ class IdentificationStageSerializer(StageSerializer):
|
|||
"show_matched_user",
|
||||
"enrollment_flow",
|
||||
"recovery_flow",
|
||||
"sources",
|
||||
]
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
# Generated by Django 3.2.3 on 2021-05-25 14:01
|
||||
|
||||
from django.apps.registry import Apps
|
||||
from django.db import migrations, models
|
||||
from django.db.backends.base.schema import BaseDatabaseSchemaEditor
|
||||
|
||||
|
||||
def assign_sources(apps: Apps, schema_editor: BaseDatabaseSchemaEditor):
|
||||
db_alias = schema_editor.connection.alias
|
||||
|
||||
IdentificationStage = apps.get_model(
|
||||
"authentik_stages_identification", "identificationstage"
|
||||
)
|
||||
Source = apps.get_model("authentik_core", "source")
|
||||
|
||||
sources = Source.objects.all()
|
||||
for stage in IdentificationStage.objects.all().using(db_alias):
|
||||
stage.sources.set(sources)
|
||||
stage.save()
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("authentik_core", "0021_alter_application_slug"),
|
||||
(
|
||||
"authentik_stages_identification",
|
||||
"0008_alter_identificationstage_user_fields",
|
||||
),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="identificationstage",
|
||||
name="sources",
|
||||
field=models.ManyToManyField(
|
||||
default=list,
|
||||
help_text="Specify which sources should be shown.",
|
||||
to="authentik_core.Source",
|
||||
),
|
||||
),
|
||||
migrations.RunPython(assign_sources),
|
||||
]
|
|
@ -7,6 +7,7 @@ from django.utils.translation import gettext_lazy as _
|
|||
from django.views import View
|
||||
from rest_framework.serializers import BaseSerializer
|
||||
|
||||
from authentik.core.models import Source
|
||||
from authentik.flows.models import Flow, Stage
|
||||
|
||||
|
||||
|
@ -71,6 +72,10 @@ class IdentificationStage(Stage):
|
|||
),
|
||||
)
|
||||
|
||||
sources = models.ManyToManyField(
|
||||
Source, default=list, help_text=_("Specify which sources should be shown.")
|
||||
)
|
||||
|
||||
@property
|
||||
def serializer(self) -> BaseSerializer:
|
||||
from authentik.stages.identification.api import IdentificationStageSerializer
|
||||
|
|
|
@ -111,7 +111,9 @@ class IdentificationStageView(ChallengeStageView):
|
|||
# Check all enabled source, add them if they have a UI Login button.
|
||||
ui_sources = []
|
||||
sources: list[Source] = (
|
||||
Source.objects.filter(enabled=True).order_by("name").select_subclasses()
|
||||
current_stage.sources.filter(enabled=True)
|
||||
.order_by("name")
|
||||
.select_subclasses()
|
||||
)
|
||||
for source in sources:
|
||||
ui_login_button = source.ui_login_button
|
||||
|
|
|
@ -18,6 +18,9 @@ class TestIdentificationStage(TestCase):
|
|||
self.user = User.objects.create(username="unittest", email="test@beryju.org")
|
||||
self.client = Client()
|
||||
|
||||
# OAuthSource for the login view
|
||||
source = OAuthSource.objects.create(name="test", slug="test")
|
||||
|
||||
self.flow = Flow.objects.create(
|
||||
name="test-identification",
|
||||
slug="test-identification",
|
||||
|
@ -27,15 +30,14 @@ class TestIdentificationStage(TestCase):
|
|||
name="identification",
|
||||
user_fields=[UserFields.E_MAIL],
|
||||
)
|
||||
self.stage.sources.set([source])
|
||||
self.stage.save()
|
||||
FlowStageBinding.objects.create(
|
||||
target=self.flow,
|
||||
stage=self.stage,
|
||||
order=0,
|
||||
)
|
||||
|
||||
# OAuthSource for the login view
|
||||
OAuthSource.objects.create(name="test", slug="test")
|
||||
|
||||
def test_valid_render(self):
|
||||
"""Test that View renders correctly"""
|
||||
response = self.client.get(
|
||||
|
|
18
schema.yml
18
schema.yml
|
@ -17489,6 +17489,12 @@ components:
|
|||
nullable: true
|
||||
description: Optional recovery flow, which is linked at the bottom of the
|
||||
page.
|
||||
sources:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
format: uuid
|
||||
description: Specify which sources should be shown.
|
||||
required:
|
||||
- component
|
||||
- name
|
||||
|
@ -17531,6 +17537,12 @@ components:
|
|||
nullable: true
|
||||
description: Optional recovery flow, which is linked at the bottom of the
|
||||
page.
|
||||
sources:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
format: uuid
|
||||
description: Specify which sources should be shown.
|
||||
required:
|
||||
- name
|
||||
IntentEnum:
|
||||
|
@ -21952,6 +21964,12 @@ components:
|
|||
nullable: true
|
||||
description: Optional recovery flow, which is linked at the bottom of the
|
||||
page.
|
||||
sources:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
format: uuid
|
||||
description: Specify which sources should be shown.
|
||||
PatchedInvitationRequest:
|
||||
type: object
|
||||
description: Invitation Serializer
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { FlowsApi, IdentificationStage, UserFieldsEnum, StagesApi, FlowsInstancesListDesignationEnum } from "authentik-api";
|
||||
import { FlowsApi, IdentificationStage, UserFieldsEnum, StagesApi, FlowsInstancesListDesignationEnum, SourcesApi } from "authentik-api";
|
||||
import { t } from "@lingui/macro";
|
||||
import { customElement } from "lit-element";
|
||||
import { html, TemplateResult } from "lit-html";
|
||||
|
@ -85,6 +85,23 @@ export class IdentificationStageForm extends ModelForm<IdentificationStage, stri
|
|||
</div>
|
||||
<p class="pf-c-form__helper-text">${t`When enabled, user fields are matched regardless of their casing.`}</p>
|
||||
</ak-form-element-horizontal>
|
||||
<ak-form-element-horizontal
|
||||
label=${t`Sources`}
|
||||
?required=${true}
|
||||
name="sources">
|
||||
<select name="users" class="pf-c-form-control" multiple>
|
||||
${until(new SourcesApi(DEFAULT_CONFIG).sourcesAllList({}).then(sources => {
|
||||
return sources.results.map(source => {
|
||||
const selected = Array.from(this.instance?.sources || []).some(su => {
|
||||
return su == source.pk;
|
||||
});
|
||||
return html`<option value=${ifDefined(source.pk)} ?selected=${selected}>${source.name}</option>`;
|
||||
});
|
||||
}), html`<option>${t`Loading...`}</option>`)}
|
||||
</select>
|
||||
<p class="pf-c-form__helper-text">${t`Select sources should be shown for users to authenticate with. This only affects web-based sources, not LDAP.`}</p>
|
||||
<p class="pf-c-form__helper-text">${t`Hold control/command to select multiple items.`}</p>
|
||||
</ak-form-element-horizontal>
|
||||
<ak-form-element-horizontal name="showMatchedUser">
|
||||
<div class="pf-c-check">
|
||||
<input type="checkbox" class="pf-c-check__input" ?checked=${first(this.instance?.showMatchedUser, true)}>
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
---
|
||||
title: Next
|
||||
---
|
||||
|
||||
## Headline Changes
|
||||
|
||||
- Duo two-factor support
|
||||
|
||||
You can now add the new `authenticator_duo` stage to configure Duo authenticators. Duo has also been added as device class to the `authenticator_validation` stage.
|
||||
|
||||
Currently, only Duo push notifications are supported. Because no additional input is required, Duo also works with the LDAP Outpost.
|
||||
|
||||
## Minor changes
|
||||
|
||||
- You can now specify which sources should be shown on an Identification stage.
|
||||
|
||||
## Upgrading
|
||||
|
||||
This release does not introduce any new requirements.
|
||||
|
||||
### docker-compose
|
||||
|
||||
Download the docker-compose file for 2021.6 from [here](https://raw.githubusercontent.com/goauthentik/authentik/version-2021.6/docker-compose.yml). Afterwards, simply run `docker-compose up -d`.
|
||||
|
||||
### Kubernetes
|
||||
|
||||
Upgrade to the latest chart version to get the new images.
|
Reference in New Issue