stage/deny: add custom message (#7144)

* stage/deny: add message

* add migration, tests and schema update

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

* add form

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

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Co-authored-by: Jens Langhammer <jens@goauthentik.io>
This commit is contained in:
Samir Musali 2023-10-18 18:13:33 +03:00 committed by GitHub
parent 4262bd6ace
commit a60f3b4b81
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 104 additions and 5 deletions

View file

@ -11,7 +11,7 @@ class DenyStageSerializer(StageSerializer):
class Meta:
model = DenyStage
fields = StageSerializer.Meta.fields
fields = StageSerializer.Meta.fields + ["deny_message"]
class DenyStageViewSet(UsedByMixin, ModelViewSet):

View file

@ -0,0 +1,17 @@
# Generated by Django 4.2.6 on 2023-10-18 09:11
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("authentik_stages_deny", "0001_initial"),
]
operations = [
migrations.AddField(
model_name="denystage",
name="deny_message",
field=models.TextField(blank=True, default=""),
),
]

View file

@ -1,5 +1,5 @@
"""deny stage models"""
from django.db import models
from django.utils.translation import gettext_lazy as _
from django.views import View
from rest_framework.serializers import BaseSerializer
@ -10,6 +10,8 @@ from authentik.flows.models import Stage
class DenyStage(Stage):
"""Cancels the current flow."""
deny_message = models.TextField(blank=True, default="")
@property
def serializer(self) -> type[BaseSerializer]:
from authentik.stages.deny.api import DenyStageSerializer

View file

@ -2,6 +2,7 @@
from django.http import HttpRequest, HttpResponse
from authentik.flows.stage import StageView
from authentik.stages.deny.models import DenyStage
class DenyStageView(StageView):
@ -9,4 +10,6 @@ class DenyStageView(StageView):
def dispatch(self, request: HttpRequest) -> HttpResponse:
"""Cancels the current flow"""
return self.executor.stage_invalid()
stage: DenyStage = self.executor.current_stage
message = self.executor.plan.context.get("deny_message", stage.deny_message)
return self.executor.stage_invalid(message)

View file

@ -45,3 +45,38 @@ class TestUserDenyStage(FlowTestCase):
)
self.assertStageResponse(response, self.flow, component="ak-stage-access-denied")
def test_message_static(self):
"""Test with a static error message"""
self.stage.deny_message = "foo"
self.stage.save()
plan = FlowPlan(flow_pk=self.flow.pk.hex, bindings=[self.binding], markers=[StageMarker()])
session = self.client.session
session[SESSION_KEY_PLAN] = plan
session.save()
response = self.client.get(
reverse("authentik_api:flow-executor", kwargs={"flow_slug": self.flow.slug})
)
self.assertStageResponse(
response, self.flow, component="ak-stage-access-denied", error_message="foo"
)
def test_message_overwrite(self):
"""Test with an overwritten error message"""
self.stage.deny_message = "foo"
self.stage.save()
plan = FlowPlan(flow_pk=self.flow.pk.hex, bindings=[self.binding], markers=[StageMarker()])
plan.context["deny_message"] = "bar"
session = self.client.session
session[SESSION_KEY_PLAN] = plan
session.save()
response = self.client.get(
reverse("authentik_api:flow-executor", kwargs={"flow_slug": self.flow.slug})
)
self.assertStageResponse(
response, self.flow, component="ak-stage-access-denied", error_message="bar"
)

View file

@ -7009,6 +7009,10 @@
]
},
"title": "Flow set"
},
"deny_message": {
"type": "string",
"title": "Deny message"
}
},
"required": []

View file

@ -23909,6 +23909,10 @@ paths:
operationId: stages_deny_list
description: DenyStage Viewset
parameters:
- in: query
name: deny_message
schema:
type: string
- in: query
name: name
schema:
@ -29786,6 +29790,8 @@ components:
type: array
items:
$ref: '#/components/schemas/FlowSet'
deny_message:
type: string
required:
- component
- meta_model_name
@ -29804,6 +29810,8 @@ components:
type: array
items:
$ref: '#/components/schemas/FlowSetRequest'
deny_message:
type: string
required:
- name
Device:
@ -35997,6 +36005,8 @@ components:
type: array
items:
$ref: '#/components/schemas/FlowSetRequest'
deny_message:
type: string
PatchedDockerServiceConnectionRequest:
type: object
description: DockerServiceConnection Serializer

View file

@ -39,7 +39,8 @@ export class DenyStageForm extends ModelForm<DenyStage, string> {
}
renderForm(): TemplateResult {
return html` <span>
return html`
<span>
${msg(
"Statically deny the flow. To use this stage effectively, disable *Evaluate when flow is planned* on the respective binding.",
)}
@ -51,6 +52,23 @@ export class DenyStageForm extends ModelForm<DenyStage, string> {
class="pf-c-form-control"
required
/>
</ak-form-element-horizontal>`;
</ak-form-element-horizontal>
<ak-form-group .expanded=${true}>
<span slot="header"> ${msg("Stage-specific settings")} </span>
<div slot="body" class="pf-c-form">
<ak-form-element-horizontal label=${msg("Deny message")} name="denyMessage">
<input
type="text"
value="${ifDefined(this.instance?.denyMessage || "")}"
class="pf-c-form-control"
required
/>
<p class="pf-c-form__helper-text">
${msg("Message shown when this stage is run.")}
</p>
</ak-form-element-horizontal>
</div>
</ak-form-group>
`;
}
}

View file

@ -98,6 +98,16 @@ URL that the form will be submitted to.
Key-value pairs of the data that is included in the form and will be submitted to `url`.
#### Deny stage
##### `deny_message` (string)
:::info
Requires authentik 2023.10
:::
Optionally overwrite the deny message shown, has a higher priority than the message configured in the stage.
#### User write stage
##### `groups` (List of [Group objects](../../user-group/group.md))