Skip to content

Commit

Permalink
flows: denied action (#3194)
Browse files Browse the repository at this point in the history
  • Loading branch information
BeryJu committed Jul 2, 2022
1 parent c39a593 commit 17d33f4
Show file tree
Hide file tree
Showing 23 changed files with 564 additions and 168 deletions.
10 changes: 10 additions & 0 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,16 @@
"args": ["install"],
"group": "build",
},
{
"label": "authentik: i18n-extract",
"command": "poetry",
"args": [
"run",
"make",
"i18n-extract"
],
"group": "build",
},
{
"label": "authentik[website]: format",
"command": "make",
Expand Down
9 changes: 4 additions & 5 deletions authentik/core/tests/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,13 @@
from authentik.tenants.models import Tenant


def create_test_flow(designation: FlowDesignation = FlowDesignation.STAGE_CONFIGURATION) -> Flow:
def create_test_flow(
designation: FlowDesignation = FlowDesignation.STAGE_CONFIGURATION, **kwargs
) -> Flow:
"""Generate a flow that can be used for testing"""
uid = generate_id(10)
return Flow.objects.create(
name=uid,
title=uid,
slug=slugify(uid),
designation=designation,
name=uid, title=uid, slug=slugify(uid), designation=designation, **kwargs
)


Expand Down
5 changes: 3 additions & 2 deletions authentik/flows/api/flows.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ class Meta:
"compatibility_mode",
"export_url",
"layout",
"denied_action",
]
extra_kwargs = {
"background": {"read_only": True},
Expand Down Expand Up @@ -110,8 +111,8 @@ class FlowViewSet(UsedByMixin, ModelViewSet):
serializer_class = FlowSerializer
lookup_field = "slug"
ordering = ["slug", "name"]
search_fields = ["name", "slug", "designation", "title"]
filterset_fields = ["flow_uuid", "name", "slug", "designation"]
search_fields = ["name", "slug", "designation", "title", "denied_action"]
filterset_fields = ["flow_uuid", "name", "slug", "designation", "denied_action"]

@permission_required(None, ["authentik_flows.view_flow_cache"])
@extend_schema(responses={200: CacheSerializer(many=False)})
Expand Down
26 changes: 26 additions & 0 deletions authentik/flows/migrations/0023_flow_denied_action.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Generated by Django 4.0.5 on 2022-07-02 12:42

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
("authentik_flows", "0022_flow_layout"),
]

operations = [
migrations.AddField(
model_name="flow",
name="denied_action",
field=models.TextField(
choices=[
("message_continue", "Message Continue"),
("message", "Message"),
("continue", "Continue"),
],
default="message_continue",
help_text="Configure what should happen when a flow denies access to a user.",
),
),
]
32 changes: 14 additions & 18 deletions authentik/flows/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
from uuid import uuid4

from django.db import models
from django.http import HttpRequest
from django.utils.translation import gettext_lazy as _
from model_utils.managers import InheritanceManager
from rest_framework.serializers import BaseSerializer
Expand Down Expand Up @@ -40,6 +39,14 @@ class InvalidResponseAction(models.TextChoices):
RESTART_WITH_CONTEXT = "restart_with_context"


class FlowDeniedAction(models.TextChoices):
"""Configure what response is given to denied flow executions"""

MESSAGE_CONTINUE = "message_continue"
MESSAGE = "message"
CONTINUE = "continue"


class FlowDesignation(models.TextChoices):
"""Designation of what a Flow should be used for. At a later point, this
should be replaced by a database entry."""
Expand Down Expand Up @@ -139,6 +146,12 @@ class Flow(SerializerModel, PolicyBindingModel):
),
)

denied_action = models.TextField(
choices=FlowDeniedAction.choices,
default=FlowDeniedAction.MESSAGE_CONTINUE,
help_text=_("Configure what should happen when a flow denies access to a user."),
)

@property
def background_url(self) -> str:
"""Get the URL to the background image. If the name is /static or starts with http
Expand All @@ -157,23 +170,6 @@ def serializer(self) -> BaseSerializer:

return FlowSerializer

@staticmethod
def with_policy(request: HttpRequest, **flow_filter) -> Optional["Flow"]:
"""Get a Flow by `**flow_filter` and check if the request from `request` can access it."""
from authentik.policies.engine import PolicyEngine

flows = Flow.objects.filter(**flow_filter).order_by("slug")
for flow in flows:
engine = PolicyEngine(flow, request.user, request)
engine.build()
result = engine.result
if result.passing:
LOGGER.debug("with_policy: flow passing", flow=flow)
return flow
LOGGER.warning("with_policy: flow not passing", flow=flow, messages=result.messages)
LOGGER.debug("with_policy: no flow found", filters=flow_filter)
return None

def __str__(self) -> str:
return f"Flow {self.name} ({self.slug})"

Expand Down

0 comments on commit 17d33f4

Please sign in to comment.