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

flows: more tests #11587

Merged
merged 2 commits into from
Dec 20, 2024
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
147 changes: 118 additions & 29 deletions authentik/flows/tests/test_executor.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
from django.test.client import RequestFactory
from django.urls import reverse

from authentik.core.models import User
from authentik.core.tests.utils import create_test_flow
from authentik.core.models import Group, User
from authentik.core.tests.utils import create_test_flow, create_test_user

Check warning on line 11 in authentik/flows/tests/test_executor.py

View check run for this annotation

Codecov / codecov/patch

authentik/flows/tests/test_executor.py#L10-L11

Added lines #L10 - L11 were not covered by tests
from authentik.flows.markers import ReevaluateMarker, StageMarker
from authentik.flows.models import (
FlowDeniedAction,
Expand Down Expand Up @@ -255,7 +255,11 @@
)

binding = FlowStageBinding.objects.create(
target=flow, stage=DummyStage.objects.create(name=generate_id()), order=0
target=flow,
stage=DummyStage.objects.create(name=generate_id()),
order=0,
evaluate_on_plan=True,
re_evaluate_policies=False,
)
binding2 = FlowStageBinding.objects.create(
target=flow,
Expand All @@ -278,8 +282,8 @@
self.assertEqual(plan.bindings[0], binding)
self.assertEqual(plan.bindings[1], binding2)

self.assertIsInstance(plan.markers[0], StageMarker)
self.assertIsInstance(plan.markers[1], ReevaluateMarker)
self.assertEqual(plan.markers[0].__class__, StageMarker)
self.assertEqual(plan.markers[1].__class__, ReevaluateMarker)

Check warning on line 286 in authentik/flows/tests/test_executor.py

View check run for this annotation

Codecov / codecov/patch

authentik/flows/tests/test_executor.py#L285-L286

Added lines #L285 - L286 were not covered by tests

# Second request, this passes the first dummy stage
response = self.client.post(exec_url)
Expand All @@ -301,7 +305,11 @@
)

binding = FlowStageBinding.objects.create(
target=flow, stage=DummyStage.objects.create(name=generate_id()), order=0
target=flow,
stage=DummyStage.objects.create(name=generate_id()),
order=0,
evaluate_on_plan=True,
re_evaluate_policies=False,
)
binding2 = FlowStageBinding.objects.create(
target=flow,
Expand All @@ -310,7 +318,11 @@
re_evaluate_policies=True,
)
binding3 = FlowStageBinding.objects.create(
target=flow, stage=DummyStage.objects.create(name=generate_id()), order=2
target=flow,
stage=DummyStage.objects.create(name=generate_id()),
order=2,
evaluate_on_plan=True,
re_evaluate_policies=False,
)

PolicyBinding.objects.create(policy=false_policy, target=binding2, order=0)
Expand All @@ -328,9 +340,9 @@
self.assertEqual(plan.bindings[1], binding2)
self.assertEqual(plan.bindings[2], binding3)

self.assertIsInstance(plan.markers[0], StageMarker)
self.assertIsInstance(plan.markers[1], ReevaluateMarker)
self.assertIsInstance(plan.markers[2], StageMarker)
self.assertEqual(plan.markers[0].__class__, StageMarker)
self.assertEqual(plan.markers[1].__class__, ReevaluateMarker)
self.assertEqual(plan.markers[2].__class__, StageMarker)

Check warning on line 345 in authentik/flows/tests/test_executor.py

View check run for this annotation

Codecov / codecov/patch

authentik/flows/tests/test_executor.py#L343-L345

Added lines #L343 - L345 were not covered by tests

# Second request, this passes the first dummy stage
response = self.client.post(exec_url)
Expand All @@ -341,8 +353,8 @@
self.assertEqual(plan.bindings[0], binding2)
self.assertEqual(plan.bindings[1], binding3)

self.assertIsInstance(plan.markers[0], StageMarker)
self.assertIsInstance(plan.markers[1], StageMarker)
self.assertEqual(plan.markers[0].__class__, ReevaluateMarker)
self.assertEqual(plan.markers[1].__class__, StageMarker)

Check warning on line 357 in authentik/flows/tests/test_executor.py

View check run for this annotation

Codecov / codecov/patch

authentik/flows/tests/test_executor.py#L356-L357

Added lines #L356 - L357 were not covered by tests

# third request, this should trigger the re-evaluate
# We do this request without the patch, so the policy results in false
Expand All @@ -360,7 +372,11 @@
)

binding = FlowStageBinding.objects.create(
target=flow, stage=DummyStage.objects.create(name=generate_id()), order=0
target=flow,
stage=DummyStage.objects.create(name=generate_id()),
order=0,
evaluate_on_plan=True,
re_evaluate_policies=False,
)
binding2 = FlowStageBinding.objects.create(
target=flow,
Expand All @@ -369,7 +385,11 @@
re_evaluate_policies=True,
)
binding3 = FlowStageBinding.objects.create(
target=flow, stage=DummyStage.objects.create(name=generate_id()), order=2
target=flow,
stage=DummyStage.objects.create(name=generate_id()),
order=2,
evaluate_on_plan=True,
re_evaluate_policies=False,
)

PolicyBinding.objects.create(policy=true_policy, target=binding2, order=0)
Expand All @@ -387,9 +407,9 @@
self.assertEqual(plan.bindings[1], binding2)
self.assertEqual(plan.bindings[2], binding3)

self.assertIsInstance(plan.markers[0], StageMarker)
self.assertIsInstance(plan.markers[1], ReevaluateMarker)
self.assertIsInstance(plan.markers[2], StageMarker)
self.assertEqual(plan.markers[0].__class__, StageMarker)
self.assertEqual(plan.markers[1].__class__, ReevaluateMarker)
self.assertEqual(plan.markers[2].__class__, StageMarker)

Check warning on line 412 in authentik/flows/tests/test_executor.py

View check run for this annotation

Codecov / codecov/patch

authentik/flows/tests/test_executor.py#L410-L412

Added lines #L410 - L412 were not covered by tests

# Second request, this passes the first dummy stage
response = self.client.post(exec_url)
Expand All @@ -400,8 +420,8 @@
self.assertEqual(plan.bindings[0], binding2)
self.assertEqual(plan.bindings[1], binding3)

self.assertIsInstance(plan.markers[0], StageMarker)
self.assertIsInstance(plan.markers[1], StageMarker)
self.assertEqual(plan.markers[0].__class__, ReevaluateMarker)
self.assertEqual(plan.markers[1].__class__, StageMarker)

Check warning on line 424 in authentik/flows/tests/test_executor.py

View check run for this annotation

Codecov / codecov/patch

authentik/flows/tests/test_executor.py#L423-L424

Added lines #L423 - L424 were not covered by tests

# Third request, this passes the first dummy stage
response = self.client.post(exec_url)
Expand All @@ -411,7 +431,7 @@

self.assertEqual(plan.bindings[0], binding3)

self.assertIsInstance(plan.markers[0], StageMarker)
self.assertEqual(plan.markers[0].__class__, StageMarker)

Check warning on line 434 in authentik/flows/tests/test_executor.py

View check run for this annotation

Codecov / codecov/patch

authentik/flows/tests/test_executor.py#L434

Added line #L434 was not covered by tests

# third request, this should trigger the re-evaluate
# We do this request without the patch, so the policy results in false
Expand All @@ -429,7 +449,11 @@
)

binding = FlowStageBinding.objects.create(
target=flow, stage=DummyStage.objects.create(name=generate_id()), order=0
target=flow,
stage=DummyStage.objects.create(name=generate_id()),
order=0,
evaluate_on_plan=True,
re_evaluate_policies=False,
)
binding2 = FlowStageBinding.objects.create(
target=flow,
Expand All @@ -444,7 +468,11 @@
re_evaluate_policies=True,
)
binding4 = FlowStageBinding.objects.create(
target=flow, stage=DummyStage.objects.create(name=generate_id()), order=2
target=flow,
stage=DummyStage.objects.create(name=generate_id()),
order=2,
evaluate_on_plan=True,
re_evaluate_policies=False,
)

PolicyBinding.objects.create(policy=false_policy, target=binding2, order=0)
Expand All @@ -465,10 +493,10 @@
self.assertEqual(plan.bindings[2], binding3)
self.assertEqual(plan.bindings[3], binding4)

self.assertIsInstance(plan.markers[0], StageMarker)
self.assertIsInstance(plan.markers[1], ReevaluateMarker)
self.assertIsInstance(plan.markers[2], ReevaluateMarker)
self.assertIsInstance(plan.markers[3], StageMarker)
self.assertEqual(plan.markers[0].__class__, StageMarker)
self.assertEqual(plan.markers[1].__class__, ReevaluateMarker)
self.assertEqual(plan.markers[2].__class__, ReevaluateMarker)
self.assertEqual(plan.markers[3].__class__, StageMarker)

Check warning on line 499 in authentik/flows/tests/test_executor.py

View check run for this annotation

Codecov / codecov/patch

authentik/flows/tests/test_executor.py#L496-L499

Added lines #L496 - L499 were not covered by tests

# Second request, this passes the first dummy stage
response = self.client.post(exec_url)
Expand Down Expand Up @@ -519,9 +547,9 @@
)
# Stage 0 is a deny stage that is added dynamically
# when the reputation policy says so
deny_stage = DenyStage.objects.create(name="deny")
deny_stage = DenyStage.objects.create(name=generate_id())

Check warning on line 550 in authentik/flows/tests/test_executor.py

View check run for this annotation

Codecov / codecov/patch

authentik/flows/tests/test_executor.py#L550

Added line #L550 was not covered by tests
reputation_policy = ReputationPolicy.objects.create(
name="reputation", threshold=-1, check_ip=False
name=generate_id(), threshold=-1, check_ip=False
)
deny_binding = FlowStageBinding.objects.create(
target=flow,
Expand All @@ -534,7 +562,7 @@

# Stage 1 is an identification stage
ident_stage = IdentificationStage.objects.create(
name="ident",
name=generate_id(),
user_fields=[UserFields.E_MAIL],
pretend_user_exists=False,
)
Expand All @@ -559,3 +587,64 @@
)
response = self.client.post(exec_url, {"uid_field": "invalid-string"}, follow=True)
self.assertStageResponse(response, flow, component="ak-stage-access-denied")

def test_re_evaluate_group_binding(self):

Check warning on line 591 in authentik/flows/tests/test_executor.py

View check run for this annotation

Codecov / codecov/patch

authentik/flows/tests/test_executor.py#L591

Added line #L591 was not covered by tests
"""Test re-evaluate stage binding that has a policy binding to a group"""
flow = create_test_flow()

Check warning on line 593 in authentik/flows/tests/test_executor.py

View check run for this annotation

Codecov / codecov/patch

authentik/flows/tests/test_executor.py#L593

Added line #L593 was not covered by tests

user_group_membership = create_test_user()
user_direct_binding = create_test_user()
user_other = create_test_user()

Check warning on line 597 in authentik/flows/tests/test_executor.py

View check run for this annotation

Codecov / codecov/patch

authentik/flows/tests/test_executor.py#L595-L597

Added lines #L595 - L597 were not covered by tests

group_a = Group.objects.create(name=generate_id())
user_group_membership.ak_groups.add(group_a)

Check warning on line 600 in authentik/flows/tests/test_executor.py

View check run for this annotation

Codecov / codecov/patch

authentik/flows/tests/test_executor.py#L599-L600

Added lines #L599 - L600 were not covered by tests

# Stage 0 is an identification stage
ident_stage = IdentificationStage.objects.create(

Check warning on line 603 in authentik/flows/tests/test_executor.py

View check run for this annotation

Codecov / codecov/patch

authentik/flows/tests/test_executor.py#L603

Added line #L603 was not covered by tests
name=generate_id(),
user_fields=[UserFields.USERNAME],
pretend_user_exists=False,
)
FlowStageBinding.objects.create(

Check warning on line 608 in authentik/flows/tests/test_executor.py

View check run for this annotation

Codecov / codecov/patch

authentik/flows/tests/test_executor.py#L608

Added line #L608 was not covered by tests
target=flow,
stage=ident_stage,
order=0,
)

# Stage 1 is a dummy stage that is only shown for users in group_a
dummy_stage = DummyStage.objects.create(name=generate_id())
dummy_binding = FlowStageBinding.objects.create(target=flow, stage=dummy_stage, order=1)
PolicyBinding.objects.create(group=group_a, target=dummy_binding, order=0)
PolicyBinding.objects.create(user=user_direct_binding, target=dummy_binding, order=0)

Check warning on line 618 in authentik/flows/tests/test_executor.py

View check run for this annotation

Codecov / codecov/patch

authentik/flows/tests/test_executor.py#L615-L618

Added lines #L615 - L618 were not covered by tests

# Stage 2 is a deny stage that (in this case) only user_b will see
deny_stage = DenyStage.objects.create(name=generate_id())
FlowStageBinding.objects.create(target=flow, stage=deny_stage, order=2)

Check warning on line 622 in authentik/flows/tests/test_executor.py

View check run for this annotation

Codecov / codecov/patch

authentik/flows/tests/test_executor.py#L621-L622

Added lines #L621 - L622 were not covered by tests

exec_url = reverse("authentik_api:flow-executor", kwargs={"flow_slug": flow.slug})

Check warning on line 624 in authentik/flows/tests/test_executor.py

View check run for this annotation

Codecov / codecov/patch

authentik/flows/tests/test_executor.py#L624

Added line #L624 was not covered by tests

with self.subTest(f"Test user access through group: {user_group_membership}"):
self.client.logout()

Check warning on line 627 in authentik/flows/tests/test_executor.py

View check run for this annotation

Codecov / codecov/patch

authentik/flows/tests/test_executor.py#L626-L627

Added lines #L626 - L627 were not covered by tests
# First request, run the planner
response = self.client.get(exec_url)
self.assertStageResponse(response, flow, component="ak-stage-identification")
response = self.client.post(

Check warning on line 631 in authentik/flows/tests/test_executor.py

View check run for this annotation

Codecov / codecov/patch

authentik/flows/tests/test_executor.py#L629-L631

Added lines #L629 - L631 were not covered by tests
exec_url, {"uid_field": user_group_membership.username}, follow=True
)
self.assertStageResponse(response, flow, component="ak-stage-dummy")
with self.subTest(f"Test user access through user: {user_direct_binding}"):
self.client.logout()

Check warning on line 636 in authentik/flows/tests/test_executor.py

View check run for this annotation

Codecov / codecov/patch

authentik/flows/tests/test_executor.py#L634-L636

Added lines #L634 - L636 were not covered by tests
# First request, run the planner
response = self.client.get(exec_url)
self.assertStageResponse(response, flow, component="ak-stage-identification")
response = self.client.post(

Check warning on line 640 in authentik/flows/tests/test_executor.py

View check run for this annotation

Codecov / codecov/patch

authentik/flows/tests/test_executor.py#L638-L640

Added lines #L638 - L640 were not covered by tests
exec_url, {"uid_field": user_direct_binding.username}, follow=True
)
self.assertStageResponse(response, flow, component="ak-stage-dummy")
with self.subTest(f"Test user has no access: {user_other}"):
self.client.logout()

Check warning on line 645 in authentik/flows/tests/test_executor.py

View check run for this annotation

Codecov / codecov/patch

authentik/flows/tests/test_executor.py#L643-L645

Added lines #L643 - L645 were not covered by tests
# First request, run the planner
response = self.client.get(exec_url)
self.assertStageResponse(response, flow, component="ak-stage-identification")
response = self.client.post(exec_url, {"uid_field": user_other.username}, follow=True)
self.assertStageResponse(response, flow, component="ak-stage-access-denied")

Check warning on line 650 in authentik/flows/tests/test_executor.py

View check run for this annotation

Codecov / codecov/patch

authentik/flows/tests/test_executor.py#L647-L650

Added lines #L647 - L650 were not covered by tests
22 changes: 14 additions & 8 deletions authentik/flows/tests/test_inspector.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

from authentik.core.tests.utils import create_test_admin_user, create_test_flow
from authentik.flows.models import FlowDesignation, FlowStageBinding, InvalidResponseAction
from authentik.lib.generators import generate_id

Check warning on line 11 in authentik/flows/tests/test_inspector.py

View check run for this annotation

Codecov / codecov/patch

authentik/flows/tests/test_inspector.py#L11

Added line #L11 was not covered by tests
from authentik.stages.dummy.models import DummyStage
from authentik.stages.identification.models import IdentificationStage, UserFields

Expand All @@ -26,7 +27,7 @@

# Stage 1 is an identification stage
ident_stage = IdentificationStage.objects.create(
name="ident",
name=generate_id(),
user_fields=[UserFields.USERNAME],
)
FlowStageBinding.objects.create(
Expand All @@ -35,9 +36,8 @@
order=1,
invalid_response_action=InvalidResponseAction.RESTART_WITH_CONTEXT,
)
FlowStageBinding.objects.create(
target=flow, stage=DummyStage.objects.create(name="dummy2"), order=1
)
dummy_stage = DummyStage.objects.create(name=generate_id())
FlowStageBinding.objects.create(target=flow, stage=dummy_stage, order=1)

Check warning on line 40 in authentik/flows/tests/test_inspector.py

View check run for this annotation

Codecov / codecov/patch

authentik/flows/tests/test_inspector.py#L39-L40

Added lines #L39 - L40 were not covered by tests

res = self.client.get(
reverse("authentik_api:flow-executor", kwargs={"flow_slug": flow.slug}),
Expand Down Expand Up @@ -68,9 +68,11 @@
)
content = loads(ins.content)
self.assertEqual(content["is_completed"], False)
self.assertEqual(content["current_plan"]["current_stage"]["stage_obj"]["name"], "ident")
self.assertEqual(
content["current_plan"]["next_planned_stage"]["stage_obj"]["name"], "dummy2"
content["current_plan"]["current_stage"]["stage_obj"]["name"], ident_stage.name
)
self.assertEqual(

Check warning on line 74 in authentik/flows/tests/test_inspector.py

View check run for this annotation

Codecov / codecov/patch

authentik/flows/tests/test_inspector.py#L74

Added line #L74 was not covered by tests
content["current_plan"]["next_planned_stage"]["stage_obj"]["name"], dummy_stage.name
)

self.client.post(
Expand All @@ -84,8 +86,12 @@
)
content = loads(ins.content)
self.assertEqual(content["is_completed"], False)
self.assertEqual(content["plans"][0]["current_stage"]["stage_obj"]["name"], "ident")
self.assertEqual(content["current_plan"]["current_stage"]["stage_obj"]["name"], "dummy2")
self.assertEqual(

Check warning on line 89 in authentik/flows/tests/test_inspector.py

View check run for this annotation

Codecov / codecov/patch

authentik/flows/tests/test_inspector.py#L89

Added line #L89 was not covered by tests
content["plans"][0]["current_stage"]["stage_obj"]["name"], ident_stage.name
)
self.assertEqual(

Check warning on line 92 in authentik/flows/tests/test_inspector.py

View check run for this annotation

Codecov / codecov/patch

authentik/flows/tests/test_inspector.py#L92

Added line #L92 was not covered by tests
content["current_plan"]["current_stage"]["stage_obj"]["name"], dummy_stage.name
)
self.assertEqual(
content["current_plan"]["plan_context"]["pending_user"]["username"], self.admin.username
)
18 changes: 12 additions & 6 deletions authentik/flows/tests/test_planner.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
cache_key,
)
from authentik.flows.stage import StageView
from authentik.lib.generators import generate_id

Check warning on line 32 in authentik/flows/tests/test_planner.py

View check run for this annotation

Codecov / codecov/patch

authentik/flows/tests/test_planner.py#L32

Added line #L32 was not covered by tests
from authentik.lib.tests.utils import dummy_get_response
from authentik.outposts.apps import MANAGED_OUTPOST
from authentik.outposts.models import Outpost
Expand Down Expand Up @@ -153,7 +154,7 @@
"""Test planner cache"""
flow = create_test_flow(FlowDesignation.AUTHENTICATION)
FlowStageBinding.objects.create(
target=flow, stage=DummyStage.objects.create(name="dummy"), order=0
target=flow, stage=DummyStage.objects.create(name=generate_id()), order=0
)
request = self.request_factory.get(
reverse("authentik_api:flow-executor", kwargs={"flow_slug": flow.slug}),
Expand All @@ -172,7 +173,7 @@
"""Test planner with default_context"""
flow = create_test_flow()
FlowStageBinding.objects.create(
target=flow, stage=DummyStage.objects.create(name="dummy"), order=0
target=flow, stage=DummyStage.objects.create(name=generate_id()), order=0
)

user = User.objects.create(username="test-user")
Expand All @@ -191,7 +192,7 @@

FlowStageBinding.objects.create(
target=flow,
stage=DummyStage.objects.create(name="dummy1"),
stage=DummyStage.objects.create(name=generate_id()),
order=0,
re_evaluate_policies=True,
)
Expand All @@ -204,19 +205,22 @@
planner = FlowPlanner(flow)
plan = planner.plan(request)

self.assertIsInstance(plan.markers[0], ReevaluateMarker)
self.assertEqual(plan.markers[0].__class__, ReevaluateMarker)

Check warning on line 208 in authentik/flows/tests/test_planner.py

View check run for this annotation

Codecov / codecov/patch

authentik/flows/tests/test_planner.py#L208

Added line #L208 was not covered by tests

def test_planner_reevaluate_actual(self):
"""Test planner with re-evaluate"""
flow = create_test_flow()
false_policy = DummyPolicy.objects.create(result=False, wait_min=1, wait_max=2)

binding = FlowStageBinding.objects.create(
target=flow, stage=DummyStage.objects.create(name="dummy1"), order=0
target=flow,
stage=DummyStage.objects.create(name=generate_id()),
order=0,
re_evaluate_policies=False,
)
binding2 = FlowStageBinding.objects.create(
target=flow,
stage=DummyStage.objects.create(name="dummy2"),
stage=DummyStage.objects.create(name=generate_id()),
order=1,
re_evaluate_policies=True,
)
Expand All @@ -240,6 +244,8 @@
self.assertEqual(plan.bindings[0], binding)
self.assertEqual(plan.bindings[1], binding2)

self.assertEqual(plan.markers[0].__class__, StageMarker)
self.assertEqual(plan.markers[1].__class__, ReevaluateMarker)

Check warning on line 248 in authentik/flows/tests/test_planner.py

View check run for this annotation

Codecov / codecov/patch

authentik/flows/tests/test_planner.py#L247-L248

Added lines #L247 - L248 were not covered by tests
self.assertIsInstance(plan.markers[0], StageMarker)
self.assertIsInstance(plan.markers[1], ReevaluateMarker)

Expand Down
Loading