Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

stages/identification: add option to pretend user exists #7610

Merged
merged 4 commits into from
Nov 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .github/workflows/gha-cache-cleanup.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ on:
types:
- closed

permissions:
# Permission to delete cache
actions: write

jobs:
cleanup:
runs-on: ubuntu-latest
Expand Down
4 changes: 4 additions & 0 deletions .github/workflows/translation-advice.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ on:
- "!locale/en/**"
- "web/xliff/**"

permissions:
# Permission to write comment
pull-requests: write

jobs:
post-comment:
runs-on: ubuntu-latest
Expand Down
4 changes: 4 additions & 0 deletions .github/workflows/translation-rename.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ on:
pull_request:
types: [opened, reopened]

permissions:
# Permission to rename PR
pull-requests: write

jobs:
rename_pr:
runs-on: ubuntu-latest
Expand Down
1 change: 1 addition & 0 deletions authentik/flows/tests/test_executor.py
Original file line number Diff line number Diff line change
Expand Up @@ -472,6 +472,7 @@ def test_invalid_restart(self):
ident_stage = IdentificationStage.objects.create(
name="ident",
user_fields=[UserFields.E_MAIL],
pretend_user_exists=False,
)
FlowStageBinding.objects.create(
target=flow,
Expand Down
10 changes: 9 additions & 1 deletion authentik/lib/avatars.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,15 @@ def generate_avatar_from_name(

def avatar_mode_generated(user: "User", mode: str) -> Optional[str]:
"""Wrapper that converts generated avatar to base64 svg"""
svg = generate_avatar_from_name(user.name if user.name.strip() != "" else "a k")
# By default generate based off of user's display name
name = user.name.strip()
if name == "":
# Fallback to username
name = user.username.strip()
# If we still don't have anything, fallback to `a k`
if name == "":
name = "a k"
svg = generate_avatar_from_name(name)
return f"data:image/svg+xml;base64,{b64encode(svg.encode('utf-8')).decode('utf-8')}"


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,14 @@ class Migration(migrations.Migration):
name="totpdevice",
options={"verbose_name": "TOTP Device", "verbose_name_plural": "TOTP Devices"},
),
migrations.AlterField(
model_name="authenticatortotpstage",
name="digits",
field=models.IntegerField(
choices=[
("6", "6 digits, widely compatible"),
("8", "8 digits, not compatible with apps like Google Authenticator"),
]
),
),
]
1 change: 1 addition & 0 deletions authentik/stages/identification/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ class Meta:
"passwordless_flow",
"sources",
"show_source_labels",
"pretend_user_exists",
]


Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Generated by Django 4.2.7 on 2023-11-17 16:32

from django.db import migrations, models


class Migration(migrations.Migration):
dependencies = [
(
"authentik_stages_identification",
"0002_auto_20200530_2204_squashed_0013_identificationstage_passwordless_flow",
),
]

operations = [
migrations.AddField(
model_name="identificationstage",
name="pretend_user_exists",
field=models.BooleanField(
default=True,
help_text="When enabled, the stage will succeed and continue even when incorrect user info is entered.",
),
),
]
7 changes: 7 additions & 0 deletions authentik/stages/identification/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,13 @@ class IdentificationStage(Stage):
"entered will be shown"
),
)
pretend_user_exists = models.BooleanField(
default=True,
help_text=_(
"When enabled, the stage will succeed and continue even when incorrect user info "
"is entered."
),
)

enrollment_flow = models.ForeignKey(
Flow,
Expand Down
4 changes: 2 additions & 2 deletions authentik/stages/identification/stage.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,8 +121,8 @@ def validate(self, attrs: dict[str, Any]) -> dict[str, Any]:
self.pre_user = self.stage.executor.plan.context[PLAN_CONTEXT_PENDING_USER]
if not current_stage.show_matched_user:
self.stage.executor.plan.context[PLAN_CONTEXT_PENDING_USER_IDENTIFIER] = uid_field
if self.stage.executor.flow.designation == FlowDesignation.RECOVERY:
# When used in a recovery flow, always continue to not disclose if a user exists
# when `pretend` is enabled, continue regardless
if current_stage.pretend_user_exists:
return attrs
raise ValidationError("Failed to authenticate.")
self.pre_user = pre_user
Expand Down
21 changes: 21 additions & 0 deletions authentik/stages/identification/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ def setUp(self):
self.stage = IdentificationStage.objects.create(
name="identification",
user_fields=[UserFields.E_MAIL],
pretend_user_exists=False,
)
self.stage.sources.set([source])
self.stage.save()
Expand Down Expand Up @@ -106,6 +107,26 @@ def test_invalid_with_username(self):
form_data,
)
self.assertEqual(response.status_code, 200)
self.assertStageResponse(
response,
self.flow,
component="ak-stage-identification",
response_errors={
"non_field_errors": [{"string": "Failed to authenticate.", "code": "invalid"}]
},
)

def test_invalid_with_username_pretend(self):
"""Test invalid with username (user exists but stage only allows email)"""
self.stage.pretend_user_exists = True
self.stage.save()
form_data = {"uid_field": self.user.username}
response = self.client.post(
reverse("authentik_api:flow-executor", kwargs={"flow_slug": self.flow.slug}),
form_data,
)
self.assertEqual(response.status_code, 200)
self.assertStageRedirects(response, reverse("authentik_core:root-redirect"))

def test_invalid_no_fields(self):
"""Test invalid with username (no user fields are enabled)"""
Expand Down
5 changes: 5 additions & 0 deletions blueprints/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -7425,6 +7425,11 @@
"show_source_labels": {
"type": "boolean",
"title": "Show source labels"
},
"pretend_user_exists": {
"type": "boolean",
"title": "Pretend user exists",
"description": "When enabled, the stage will succeed and continue even when incorrect user info is entered."
}
},
"required": []
Expand Down
12 changes: 12 additions & 0 deletions schema.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32013,6 +32013,10 @@ components:
description: Specify which sources should be shown.
show_source_labels:
type: boolean
pretend_user_exists:
type: boolean
description: When enabled, the stage will succeed and continue even when
incorrect user info is entered.
required:
- component
- meta_model_name
Expand Down Expand Up @@ -32077,6 +32081,10 @@ components:
description: Specify which sources should be shown.
show_source_labels:
type: boolean
pretend_user_exists:
type: boolean
description: When enabled, the stage will succeed and continue even when
incorrect user info is entered.
required:
- name
InstallID:
Expand Down Expand Up @@ -36560,6 +36568,10 @@ components:
description: Specify which sources should be shown.
show_source_labels:
type: boolean
pretend_user_exists:
type: boolean
description: When enabled, the stage will succeed and continue even when
incorrect user info is entered.
PatchedInvitationRequest:
type: object
description: Invitation Serializer
Expand Down
22 changes: 21 additions & 1 deletion web/src/admin/stages/identification/IdentificationStageForm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ export class IdentificationStageForm extends ModelForm<IdentificationStage, stri
}

renderForm(): TemplateResult {
return html` <span>
return html`<span>
${msg("Let the user identify themselves with their username or Email address.")}
</span>
<ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
Expand Down Expand Up @@ -169,6 +169,26 @@ export class IdentificationStageForm extends ModelForm<IdentificationStage, stri
)}
</p>
</ak-form-element-horizontal>
<ak-form-element-horizontal name="pretendUserExists">
<label class="pf-c-switch">
<input
class="pf-c-switch__input"
type="checkbox"
?checked=${first(this.instance?.pretendUserExists, true)}
/>
<span class="pf-c-switch__toggle">
<span class="pf-c-switch__toggle-icon">
<i class="fas fa-check" aria-hidden="true"></i>
</span>
</span>
<span class="pf-c-switch__label">${msg("Pretend user exists")}</span>
</label>
<p class="pf-c-form__helper-text">
${msg(
"When enabled, the stage will always accept the given user identifier and continue.",
)}
</p>
</ak-form-element-horizontal>
<ak-form-element-horizontal name="showMatchedUser">
<label class="pf-c-switch">
<input
Expand Down
6 changes: 6 additions & 0 deletions web/xliff/de.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -6069,6 +6069,12 @@ Bindings to groups/users are checked against the user of the event.</source>
</trans-unit>
<trans-unit id="s824e0943a7104668">
<source>This user will be added to the group "<x id="0" equiv-text="${this.targetGroup.name}"/>".</source>
</trans-unit>
<trans-unit id="s62e7f6ed7d9cb3ca">
<source>Pretend user exists</source>
</trans-unit>
<trans-unit id="s52bdc80690a9a8dc">
<source>When enabled, the stage will always accept the given user identifier and continue.</source>
</trans-unit>
</body>
</file>
Expand Down
6 changes: 6 additions & 0 deletions web/xliff/en.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -6346,6 +6346,12 @@ Bindings to groups/users are checked against the user of the event.</source>
</trans-unit>
<trans-unit id="s824e0943a7104668">
<source>This user will be added to the group "<x id="0" equiv-text="${this.targetGroup.name}"/>".</source>
</trans-unit>
<trans-unit id="s62e7f6ed7d9cb3ca">
<source>Pretend user exists</source>
</trans-unit>
<trans-unit id="s52bdc80690a9a8dc">
<source>When enabled, the stage will always accept the given user identifier and continue.</source>
</trans-unit>
</body>
</file>
Expand Down
6 changes: 6 additions & 0 deletions web/xliff/es.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -5985,6 +5985,12 @@ Bindings to groups/users are checked against the user of the event.</source>
</trans-unit>
<trans-unit id="s824e0943a7104668">
<source>This user will be added to the group "<x id="0" equiv-text="${this.targetGroup.name}"/>".</source>
</trans-unit>
<trans-unit id="s62e7f6ed7d9cb3ca">
<source>Pretend user exists</source>
</trans-unit>
<trans-unit id="s52bdc80690a9a8dc">
<source>When enabled, the stage will always accept the given user identifier and continue.</source>
</trans-unit>
</body>
</file>
Expand Down
6 changes: 6 additions & 0 deletions web/xliff/fr.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -7971,6 +7971,12 @@ Les liaisons avec les groupes/utilisateurs sont vérifiées par rapport à l'uti
</trans-unit>
<trans-unit id="s824e0943a7104668">
<source>This user will be added to the group "<x id="0" equiv-text="${this.targetGroup.name}"/>".</source>
</trans-unit>
<trans-unit id="s62e7f6ed7d9cb3ca">
<source>Pretend user exists</source>
</trans-unit>
<trans-unit id="s52bdc80690a9a8dc">
<source>When enabled, the stage will always accept the given user identifier and continue.</source>
</trans-unit>
</body>
</file>
Expand Down
6 changes: 6 additions & 0 deletions web/xliff/pl.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -6193,6 +6193,12 @@ Bindings to groups/users are checked against the user of the event.</source>
</trans-unit>
<trans-unit id="s824e0943a7104668">
<source>This user will be added to the group "<x id="0" equiv-text="${this.targetGroup.name}"/>".</source>
</trans-unit>
<trans-unit id="s62e7f6ed7d9cb3ca">
<source>Pretend user exists</source>
</trans-unit>
<trans-unit id="s52bdc80690a9a8dc">
<source>When enabled, the stage will always accept the given user identifier and continue.</source>
</trans-unit>
</body>
</file>
Expand Down
6 changes: 6 additions & 0 deletions web/xliff/pseudo-LOCALE.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -7871,4 +7871,10 @@ Bindings to groups/users are checked against the user of the event.</source>
<trans-unit id="s824e0943a7104668">
<source>This user will be added to the group "<x id="0" equiv-text="${this.targetGroup.name}"/>".</source>
</trans-unit>
<trans-unit id="s62e7f6ed7d9cb3ca">
<source>Pretend user exists</source>
</trans-unit>
<trans-unit id="s52bdc80690a9a8dc">
<source>When enabled, the stage will always accept the given user identifier and continue.</source>
</trans-unit>
</body></file></xliff>
6 changes: 6 additions & 0 deletions web/xliff/tr.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -5978,6 +5978,12 @@ Bindings to groups/users are checked against the user of the event.</source>
</trans-unit>
<trans-unit id="s824e0943a7104668">
<source>This user will be added to the group "<x id="0" equiv-text="${this.targetGroup.name}"/>".</source>
</trans-unit>
<trans-unit id="s62e7f6ed7d9cb3ca">
<source>Pretend user exists</source>
</trans-unit>
<trans-unit id="s52bdc80690a9a8dc">
<source>When enabled, the stage will always accept the given user identifier and continue.</source>
</trans-unit>
</body>
</file>
Expand Down
Loading