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:
parent
4262bd6ace
commit
a60f3b4b81
|
@ -11,7 +11,7 @@ class DenyStageSerializer(StageSerializer):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = DenyStage
|
model = DenyStage
|
||||||
fields = StageSerializer.Meta.fields
|
fields = StageSerializer.Meta.fields + ["deny_message"]
|
||||||
|
|
||||||
|
|
||||||
class DenyStageViewSet(UsedByMixin, ModelViewSet):
|
class DenyStageViewSet(UsedByMixin, ModelViewSet):
|
||||||
|
|
|
@ -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=""),
|
||||||
|
),
|
||||||
|
]
|
|
@ -1,5 +1,5 @@
|
||||||
"""deny stage models"""
|
"""deny stage models"""
|
||||||
|
from django.db import models
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from django.views import View
|
from django.views import View
|
||||||
from rest_framework.serializers import BaseSerializer
|
from rest_framework.serializers import BaseSerializer
|
||||||
|
@ -10,6 +10,8 @@ from authentik.flows.models import Stage
|
||||||
class DenyStage(Stage):
|
class DenyStage(Stage):
|
||||||
"""Cancels the current flow."""
|
"""Cancels the current flow."""
|
||||||
|
|
||||||
|
deny_message = models.TextField(blank=True, default="")
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def serializer(self) -> type[BaseSerializer]:
|
def serializer(self) -> type[BaseSerializer]:
|
||||||
from authentik.stages.deny.api import DenyStageSerializer
|
from authentik.stages.deny.api import DenyStageSerializer
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
from django.http import HttpRequest, HttpResponse
|
from django.http import HttpRequest, HttpResponse
|
||||||
|
|
||||||
from authentik.flows.stage import StageView
|
from authentik.flows.stage import StageView
|
||||||
|
from authentik.stages.deny.models import DenyStage
|
||||||
|
|
||||||
|
|
||||||
class DenyStageView(StageView):
|
class DenyStageView(StageView):
|
||||||
|
@ -9,4 +10,6 @@ class DenyStageView(StageView):
|
||||||
|
|
||||||
def dispatch(self, request: HttpRequest) -> HttpResponse:
|
def dispatch(self, request: HttpRequest) -> HttpResponse:
|
||||||
"""Cancels the current flow"""
|
"""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)
|
||||||
|
|
|
@ -45,3 +45,38 @@ class TestUserDenyStage(FlowTestCase):
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assertStageResponse(response, self.flow, component="ak-stage-access-denied")
|
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"
|
||||||
|
)
|
||||||
|
|
|
@ -7009,6 +7009,10 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"title": "Flow set"
|
"title": "Flow set"
|
||||||
|
},
|
||||||
|
"deny_message": {
|
||||||
|
"type": "string",
|
||||||
|
"title": "Deny message"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": []
|
"required": []
|
||||||
|
|
10
schema.yml
10
schema.yml
|
@ -23909,6 +23909,10 @@ paths:
|
||||||
operationId: stages_deny_list
|
operationId: stages_deny_list
|
||||||
description: DenyStage Viewset
|
description: DenyStage Viewset
|
||||||
parameters:
|
parameters:
|
||||||
|
- in: query
|
||||||
|
name: deny_message
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
- in: query
|
- in: query
|
||||||
name: name
|
name: name
|
||||||
schema:
|
schema:
|
||||||
|
@ -29786,6 +29790,8 @@ components:
|
||||||
type: array
|
type: array
|
||||||
items:
|
items:
|
||||||
$ref: '#/components/schemas/FlowSet'
|
$ref: '#/components/schemas/FlowSet'
|
||||||
|
deny_message:
|
||||||
|
type: string
|
||||||
required:
|
required:
|
||||||
- component
|
- component
|
||||||
- meta_model_name
|
- meta_model_name
|
||||||
|
@ -29804,6 +29810,8 @@ components:
|
||||||
type: array
|
type: array
|
||||||
items:
|
items:
|
||||||
$ref: '#/components/schemas/FlowSetRequest'
|
$ref: '#/components/schemas/FlowSetRequest'
|
||||||
|
deny_message:
|
||||||
|
type: string
|
||||||
required:
|
required:
|
||||||
- name
|
- name
|
||||||
Device:
|
Device:
|
||||||
|
@ -35997,6 +36005,8 @@ components:
|
||||||
type: array
|
type: array
|
||||||
items:
|
items:
|
||||||
$ref: '#/components/schemas/FlowSetRequest'
|
$ref: '#/components/schemas/FlowSetRequest'
|
||||||
|
deny_message:
|
||||||
|
type: string
|
||||||
PatchedDockerServiceConnectionRequest:
|
PatchedDockerServiceConnectionRequest:
|
||||||
type: object
|
type: object
|
||||||
description: DockerServiceConnection Serializer
|
description: DockerServiceConnection Serializer
|
||||||
|
|
|
@ -39,7 +39,8 @@ export class DenyStageForm extends ModelForm<DenyStage, string> {
|
||||||
}
|
}
|
||||||
|
|
||||||
renderForm(): TemplateResult {
|
renderForm(): TemplateResult {
|
||||||
return html` <span>
|
return html`
|
||||||
|
<span>
|
||||||
${msg(
|
${msg(
|
||||||
"Statically deny the flow. To use this stage effectively, disable *Evaluate when flow is planned* on the respective binding.",
|
"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"
|
class="pf-c-form-control"
|
||||||
required
|
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>
|
||||||
|
`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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`.
|
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
|
#### User write stage
|
||||||
|
|
||||||
##### `groups` (List of [Group objects](../../user-group/group.md))
|
##### `groups` (List of [Group objects](../../user-group/group.md))
|
||||||
|
|
Reference in New Issue